diff options
1147 files changed, 21072 insertions, 9453 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java index 776d913e56cb..3cfddc6d8e2b 100644 --- a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java +++ b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java @@ -65,8 +65,12 @@ public class JobSchedulerImpl extends JobScheduler { @NonNull @Override public JobScheduler forNamespace(@NonNull String namespace) { + namespace = sanitizeNamespace(namespace); if (namespace == null) { - throw new IllegalArgumentException("namespace cannot be null"); + throw new NullPointerException("namespace cannot be null"); + } + if (namespace.isEmpty()) { + throw new IllegalArgumentException("namespace cannot be empty"); } return new JobSchedulerImpl(this, namespace); } diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 805dfafe5923..37ceb091f035 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -1382,6 +1382,12 @@ public class JobInfo implements Parcelable { * Calling this method will override any requirements previously defined * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only * want to call one of these methods. + * + * Starting in Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * an app must hold the {@link android.Manifest.permission#INTERNET} and + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} permissions to + * schedule a job that requires a network. + * * <p class="note"> * When your job executes in * {@link JobService#onStartJob(JobParameters)}, be sure to use the @@ -1438,6 +1444,11 @@ public class JobInfo implements Parcelable { * otherwise you'll use the default network which may not meet this * constraint. * + * Starting in Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * an app must hold the {@link android.Manifest.permission#INTERNET} and + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} permissions to + * schedule a job that requires a network. + * * @param networkRequest The detailed description of the kind of network * this job requires, or {@code null} if no specific kind of * network is required. Defining a {@link NetworkSpecifier} diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java index 32502eddc9f8..bf4f9a83b99c 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java @@ -481,6 +481,10 @@ public class JobParameters implements Parcelable { * such as allowing a {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over * a metered network when there is a surplus of metered data available. * + * Starting in Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * this will return {@code null} if the app does not hold the permissions specified in + * {@link JobInfo.Builder#setRequiredNetwork(NetworkRequest)}. + * * @return the network that should be used to perform any network requests * for this job, or {@code null} if this job didn't set any required * network type or if the job executed when there was no available network to use. diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java index b8847add0734..d59d430e0b78 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java @@ -270,6 +270,9 @@ public abstract class JobScheduler { * otherwise. Attempting to update a job scheduled in another namespace will not be possible * but will instead create or update the job inside the current namespace. A JobScheduler * instance dedicated to a namespace must be used to schedule or update jobs in that namespace. + * + * <p class="note">Since leading and trailing whitespace can lead to hard-to-debug issues, + * they will be {@link String#trim() trimmed}. An empty String (after trimming) is not allowed. * @see #getNamespace() */ @NonNull @@ -287,6 +290,15 @@ public abstract class JobScheduler { throw new RuntimeException("Not implemented. Must override in a subclass."); } + /** @hide */ + @Nullable + public static String sanitizeNamespace(@Nullable String namespace) { + if (namespace == null) { + return null; + } + return namespace.trim().intern(); + } + /** * Schedule a job to be executed. Will replace any currently scheduled job with the same * ID with the new information in the {@link JobInfo}. If a job with the given ID is currently 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 d94993d64995..bad4060ca775 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import android.Manifest; import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; @@ -190,6 +191,14 @@ public class JobSchedulerService extends com.android.server.SystemService @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) private static final long REQUIRE_NETWORK_CONSTRAINT_FOR_NETWORK_JOB_WORK_ITEMS = 241104082L; + /** + * Require the app to have the INTERNET and ACCESS_NETWORK_STATE permissions when scheduling + * a job with a connectivity constraint. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + static final long REQUIRE_NETWORK_PERMISSIONS_FOR_CONNECTIVITY_JOBS = 271850009L; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public static Clock sSystemClock = Clock.systemUTC(); @@ -299,6 +308,14 @@ public class JobSchedulerService extends com.android.server.SystemService private final RemoteCallbackList<IUserVisibleJobObserver> mUserVisibleJobObservers = new RemoteCallbackList<>(); + /** + * Cache of grant status of permissions, keyed by UID->PID->permission name. A missing value + * means the state has not been queried. + */ + @GuardedBy("mPermissionCache") + private final SparseArray<SparseArrayMap<String, Boolean>> mPermissionCache = + new SparseArray<>(); + private final CountQuotaTracker mQuotaTracker; private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()"; private static final String QUOTA_TRACKER_SCHEDULE_LOGGED = @@ -365,6 +382,16 @@ public class JobSchedulerService extends com.android.server.SystemService * A mapping of which uids are currently in the foreground to their effective bias. */ final SparseIntArray mUidBiasOverride = new SparseIntArray(); + /** + * A cached mapping of uids to their current capabilities. + */ + @GuardedBy("mLock") + private final SparseIntArray mUidCapabilities = new SparseIntArray(); + /** + * A cached mapping of uids to their proc states. + */ + @GuardedBy("mLock") + private final SparseIntArray mUidProcStates = new SparseIntArray(); /** * Which uids are currently performing backups, so we shouldn't allow their jobs to run. @@ -1042,6 +1069,10 @@ public class JobSchedulerService extends com.android.server.SystemService final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1); if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { + synchronized (mPermissionCache) { + // Something changed. Better clear the cached permission set. + mPermissionCache.remove(pkgUid); + } // Purge the app's jobs if the whole package was just disabled. When this is // the case the component name will be a bare package name. if (pkgName != null && pkgUid != -1) { @@ -1106,17 +1137,19 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.w(TAG, "PACKAGE_CHANGED for " + pkgName + " / uid " + pkgUid); } } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + synchronized (mPermissionCache) { + // Something changed. Better clear the cached permission set. + mPermissionCache.remove(pkgUid); + } if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { - final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); synchronized (mLock) { - mUidToPackageCache.remove(uid); - } - } else { - synchronized (mJobSchedulerStub.mPersistCache) { - mJobSchedulerStub.mPersistCache.remove(pkgUid); + mUidToPackageCache.remove(pkgUid); } } } else if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) { + synchronized (mPermissionCache) { + mPermissionCache.remove(pkgUid); + } if (DEBUG) { Slog.d(TAG, "Removing jobs for " + pkgName + " (uid=" + pkgUid + ")"); } @@ -1135,6 +1168,14 @@ public class JobSchedulerService extends com.android.server.SystemService mDebuggableApps.remove(pkgName); mConcurrencyManager.onAppRemovedLocked(pkgName, pkgUid); } + } else if (Intent.ACTION_UID_REMOVED.equals(action)) { + if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + synchronized (mLock) { + mUidBiasOverride.delete(pkgUid); + mUidCapabilities.delete(pkgUid); + mUidProcStates.delete(pkgUid); + } + } } else if (Intent.ACTION_USER_ADDED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); synchronized (mLock) { @@ -1155,6 +1196,14 @@ public class JobSchedulerService extends com.android.server.SystemService } } mConcurrencyManager.onUserRemoved(userId); + synchronized (mPermissionCache) { + for (int u = mPermissionCache.size() - 1; u >= 0; --u) { + final int uid = mPermissionCache.keyAt(u); + if (userId == UserHandle.getUserId(uid)) { + mPermissionCache.removeAt(u); + } + } + } } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { // Has this package scheduled any jobs, such that we will take action // if it were to be force-stopped? @@ -1205,7 +1254,11 @@ public class JobSchedulerService extends com.android.server.SystemService final private IUidObserver mUidObserver = new IUidObserver.Stub() { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) { - mHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget(); + final SomeArgs args = SomeArgs.obtain(); + args.argi1 = uid; + args.argi2 = procState; + args.argi3 = capability; + mHandler.obtainMessage(MSG_UID_STATE_CHANGED, args).sendToTarget(); } @Override public void onUidGone(int uid, boolean disabled) { @@ -1947,8 +2000,14 @@ public class JobSchedulerService extends com.android.server.SystemService } } - void updateUidState(int uid, int procState) { + void updateUidState(int uid, int procState, int capabilities) { + if (DEBUG) { + Slog.d(TAG, "UID " + uid + " proc state changed to " + + ActivityManager.procStateToString(procState) + + " with capabilities=" + ActivityManager.getCapabilitiesSummary(capabilities)); + } synchronized (mLock) { + mUidProcStates.put(uid, procState); final int prevBias = mUidBiasOverride.get(uid, JobInfo.BIAS_DEFAULT); if (procState == ActivityManager.PROCESS_STATE_TOP) { // Only use this if we are exactly the top app. All others can live @@ -1962,6 +2021,12 @@ public class JobSchedulerService extends com.android.server.SystemService } else { mUidBiasOverride.delete(uid); } + if (capabilities == ActivityManager.PROCESS_CAPABILITY_NONE + || procState == ActivityManager.PROCESS_STATE_NONEXISTENT) { + mUidCapabilities.delete(uid); + } else { + mUidCapabilities.put(uid, capabilities); + } final int newBias = mUidBiasOverride.get(uid, JobInfo.BIAS_DEFAULT); if (prevBias != newBias) { if (DEBUG) { @@ -1982,6 +2047,23 @@ public class JobSchedulerService extends com.android.server.SystemService } } + /** + * Return the current {@link ActivityManager#PROCESS_CAPABILITY_ALL capabilities} + * of the given UID. + */ + public int getUidCapabilities(int uid) { + synchronized (mLock) { + return mUidCapabilities.get(uid, ActivityManager.PROCESS_CAPABILITY_NONE); + } + } + + /** Return the current proc state of the given UID. */ + public int getUidProcState(int uid) { + synchronized (mLock) { + return mUidProcStates.get(uid, ActivityManager.PROCESS_STATE_UNKNOWN); + } + } + @Override public void onDeviceIdleStateChanged(boolean deviceIdle) { synchronized (mLock) { @@ -2245,6 +2327,9 @@ public class JobSchedulerService extends com.android.server.SystemService filter.addDataScheme("package"); getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, filter, null, null); + final IntentFilter uidFilter = new IntentFilter(Intent.ACTION_UID_REMOVED); + getContext().registerReceiverAsUser( + mBroadcastReceiver, UserHandle.ALL, uidFilter, null, null); final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); userFilter.addAction(Intent.ACTION_USER_ADDED); getContext().registerReceiverAsUser( @@ -2776,15 +2861,19 @@ public class JobSchedulerService extends com.android.server.SystemService break; case MSG_UID_STATE_CHANGED: { - final int uid = message.arg1; - final int procState = message.arg2; - updateUidState(uid, procState); + final SomeArgs args = (SomeArgs) message.obj; + final int uid = args.argi1; + final int procState = args.argi2; + final int capabilities = args.argi3; + updateUidState(uid, procState, capabilities); + args.recycle(); break; } case MSG_UID_GONE: { final int uid = message.arg1; final boolean disabled = message.arg2 != 0; - updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY, + ActivityManager.PROCESS_CAPABILITY_NONE); if (disabled) { cancelJobsForUid(uid, /* includeSourceApp */ true, @@ -3748,18 +3837,38 @@ public class JobSchedulerService extends com.android.server.SystemService } /** + * Returns whether the app has the permission granted. + * This currently only works for normal permissions and <b>DOES NOT</b> work for runtime + * permissions. + * TODO: handle runtime permissions + */ + private boolean hasPermission(int uid, int pid, @NonNull String permission) { + synchronized (mPermissionCache) { + SparseArrayMap<String, Boolean> pidPermissions = mPermissionCache.get(uid); + if (pidPermissions == null) { + pidPermissions = new SparseArrayMap<>(); + mPermissionCache.put(uid, pidPermissions); + } + final Boolean cached = pidPermissions.get(pid, permission); + if (cached != null) { + return cached; + } + + final int result = getContext().checkPermission(permission, pid, uid); + final boolean permissionGranted = (result == PackageManager.PERMISSION_GRANTED); + pidPermissions.add(pid, permission, permissionGranted); + return permissionGranted; + } + } + + /** * Binder stub trampoline implementation */ final class JobSchedulerStub extends IJobScheduler.Stub { - /** - * Cache determination of whether a given app can persist jobs - * key is uid of the calling app; value is undetermined/true/false - */ - private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>(); - // Enforce that only the app itself (or shared uid participant) can schedule a // job that runs one of the app's services, as well as verifying that the // named service properly requires the BIND_JOB_SERVICE permission + // TODO(141645789): merge enforceValidJobRequest() with validateJob() private void enforceValidJobRequest(int uid, int pid, JobInfo job) { final PackageManager pm = getContext() .createContextAsUser(UserHandle.getUserHandleForUid(uid), 0) @@ -3784,31 +3893,33 @@ public class JobSchedulerService extends com.android.server.SystemService throw new IllegalArgumentException( "Tried to schedule job for non-existent component: " + service); } + // If we get this far we're good to go; all we need to do now is check + // whether the app is allowed to persist its scheduled work. if (job.isPersisted() && !canPersistJobs(pid, uid)) { throw new IllegalArgumentException("Requested job cannot be persisted without" + " holding android.permission.RECEIVE_BOOT_COMPLETED permission"); } + if (job.getRequiredNetwork() != null + && CompatChanges.isChangeEnabled( + REQUIRE_NETWORK_PERMISSIONS_FOR_CONNECTIVITY_JOBS, uid)) { + // All networking, including with the local network and even local to the device, + // requires the INTERNET permission. + if (!hasPermission(uid, pid, Manifest.permission.INTERNET)) { + throw new SecurityException(Manifest.permission.INTERNET + + " required for jobs with a connectivity constraint"); + } + if (!hasPermission(uid, pid, Manifest.permission.ACCESS_NETWORK_STATE)) { + throw new SecurityException(Manifest.permission.ACCESS_NETWORK_STATE + + " required for jobs with a connectivity constraint"); + } + } } private boolean canPersistJobs(int pid, int uid) { - // If we get this far we're good to go; all we need to do now is check - // whether the app is allowed to persist its scheduled work. - final boolean canPersist; - synchronized (mPersistCache) { - Boolean cached = mPersistCache.get(uid); - if (cached != null) { - canPersist = cached.booleanValue(); - } else { - // Persisting jobs is tantamount to running at boot, so we permit - // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED - // permission - int result = getContext().checkPermission( - android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid); - canPersist = (result == PackageManager.PERMISSION_GRANTED); - mPersistCache.put(uid, canPersist); - } - } - return canPersist; + // Persisting jobs is tantamount to running at boot, so we permit + // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED + // permission + return hasPermission(uid, pid, Manifest.permission.RECEIVE_BOOT_COMPLETED); } private int validateJob(@NonNull JobInfo job, int callingUid, int callingPid, @@ -3913,6 +4024,18 @@ public class JobSchedulerService extends com.android.server.SystemService return JobScheduler.RESULT_SUCCESS; } + /** Returns a sanitized namespace if valid, or throws an exception if not. */ + private String validateNamespace(@Nullable String namespace) { + namespace = JobScheduler.sanitizeNamespace(namespace); + if (namespace != null) { + if (namespace.isEmpty()) { + throw new IllegalArgumentException("namespace cannot be empty"); + } + namespace = namespace.intern(); + } + return namespace; + } + private int validateRunUserInitiatedJobsPermission(int uid, String packageName) { final int state = getRunUserInitiatedJobsPermissionState(uid, packageName); if (state == PermissionChecker.PERMISSION_HARD_DENIED) { @@ -3960,9 +4083,7 @@ public class JobSchedulerService extends com.android.server.SystemService return result; } - if (namespace != null) { - namespace = namespace.intern(); - } + namespace = validateNamespace(namespace); final long ident = Binder.clearCallingIdentity(); try { @@ -3993,9 +4114,7 @@ public class JobSchedulerService extends com.android.server.SystemService return result; } - if (namespace != null) { - namespace = namespace.intern(); - } + namespace = validateNamespace(namespace); final long ident = Binder.clearCallingIdentity(); try { @@ -4027,14 +4146,14 @@ public class JobSchedulerService extends com.android.server.SystemService + " not permitted to schedule jobs for other apps"); } + enforceValidJobRequest(callerUid, callerPid, job); + int result = validateJob(job, callerUid, callerPid, userId, packageName, null); if (result != JobScheduler.RESULT_SUCCESS) { return result; } - if (namespace != null) { - namespace = namespace.intern(); - } + namespace = validateNamespace(namespace); final long ident = Binder.clearCallingIdentity(); try { @@ -4071,7 +4190,8 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { return new ParceledListSlice<>( - JobSchedulerService.this.getPendingJobsInNamespace(uid, namespace)); + JobSchedulerService.this.getPendingJobsInNamespace(uid, + validateNamespace(namespace))); } finally { Binder.restoreCallingIdentity(ident); } @@ -4083,7 +4203,8 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { - return JobSchedulerService.this.getPendingJob(uid, namespace, jobId); + return JobSchedulerService.this.getPendingJob( + uid, validateNamespace(namespace), jobId); } finally { Binder.restoreCallingIdentity(ident); } @@ -4095,7 +4216,8 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { - return JobSchedulerService.this.getPendingJobReason(uid, namespace, jobId); + return JobSchedulerService.this.getPendingJobReason( + uid, validateNamespace(namespace), jobId); } finally { Binder.restoreCallingIdentity(ident); } @@ -4125,7 +4247,7 @@ public class JobSchedulerService extends com.android.server.SystemService JobSchedulerService.this.cancelJobsForUid(uid, // Documentation says only jobs scheduled BY the app will be cancelled /* includeSourceApp */ false, - /* namespaceOnly */ true, namespace, + /* namespaceOnly */ true, validateNamespace(namespace), JobParameters.STOP_REASON_CANCELLED_BY_APP, JobParameters.INTERNAL_STOP_REASON_CANCELED, "cancelAllInNamespace() called by app, callingUid=" + uid); @@ -4140,7 +4262,7 @@ public class JobSchedulerService extends com.android.server.SystemService final long ident = Binder.clearCallingIdentity(); try { - JobSchedulerService.this.cancelJob(uid, namespace, jobId, uid, + JobSchedulerService.this.cancelJob(uid, validateNamespace(namespace), jobId, uid, JobParameters.STOP_REASON_CANCELLED_BY_APP); } finally { Binder.restoreCallingIdentity(ident); @@ -4836,6 +4958,25 @@ public class JobSchedulerService extends com.android.server.SystemService pw.decreaseIndent(); } + boolean procStatePrinted = false; + for (int i = 0; i < mUidProcStates.size(); i++) { + int uid = mUidProcStates.keyAt(i); + if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) { + if (!procStatePrinted) { + procStatePrinted = true; + pw.println(); + pw.println("Uid proc states:"); + pw.increaseIndent(); + } + pw.print(UserHandle.formatUid(uid)); + pw.print(": "); + pw.println(ActivityManager.procStateToString(mUidProcStates.valueAt(i))); + } + } + if (procStatePrinted) { + pw.decreaseIndent(); + } + boolean overridePrinted = false; for (int i = 0; i < mUidBiasOverride.size(); i++) { int uid = mUidBiasOverride.keyAt(i); @@ -4854,6 +4995,25 @@ public class JobSchedulerService extends com.android.server.SystemService pw.decreaseIndent(); } + boolean capabilitiesPrinted = false; + for (int i = 0; i < mUidCapabilities.size(); i++) { + int uid = mUidCapabilities.keyAt(i); + if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) { + if (!capabilitiesPrinted) { + capabilitiesPrinted = true; + pw.println(); + pw.println("Uid capabilities:"); + pw.increaseIndent(); + } + pw.print(UserHandle.formatUid(uid)); + pw.print(": "); + pw.println(ActivityManager.getCapabilitiesSummary(mUidCapabilities.valueAt(i))); + } + } + if (capabilitiesPrinted) { + pw.decreaseIndent(); + } + boolean uidMapPrinted = false; for (int i = 0; i < mUidToPackageCache.size(); ++i) { final int uid = mUidToPackageCache.keyAt(i); 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 b080bf31fed4..8355e9c6da99 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -21,6 +21,7 @@ import static android.app.job.JobInfo.getPriorityString; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import android.Manifest; import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.Nullable; @@ -39,6 +40,7 @@ import android.compat.annotation.EnabledAfter; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.PermissionChecker; import android.content.ServiceConnection; import android.net.Network; import android.net.Uri; @@ -339,12 +341,13 @@ public final class JobServiceContext implements ServiceConnection { job.changedAuthorities.toArray(triggeredAuthorities); } final JobInfo ji = job.getJob(); + final Network passedNetwork = canGetNetworkInformation(job) ? job.network : null; mParams = new JobParameters(mRunningCallback, job.getNamespace(), job.getJobId(), ji.getExtras(), ji.getTransientExtras(), ji.getClipData(), ji.getClipGrantFlags(), isDeadlineExpired, job.shouldTreatAsExpeditedJob(), job.shouldTreatAsUserInitiatedJob(), triggeredUris, triggeredAuthorities, - job.network); + passedNetwork); mExecutionStartTimeElapsed = sElapsedRealtimeClock.millis(); mMinExecutionGuaranteeMillis = mService.getMinJobExecutionGuaranteeMs(job); mMaxExecutionTimeMillis = @@ -390,23 +393,27 @@ public final class JobServiceContext implements ServiceConnection { .setFlags(Intent.FLAG_FROM_BACKGROUND); boolean binding = false; try { - final int bindFlags; + final Context.BindServiceFlags bindFlags; if (job.shouldTreatAsUserInitiatedJob()) { - // TODO (191785864, 261999509): add an appropriate flag so user-initiated jobs - // can bypass data saver - bindFlags = Context.BIND_AUTO_CREATE - | Context.BIND_ALMOST_PERCEPTIBLE - | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS - | Context.BIND_NOT_APP_COMPONENT_USAGE; + bindFlags = Context.BindServiceFlags.of( + Context.BIND_AUTO_CREATE + | Context.BIND_ALMOST_PERCEPTIBLE + | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS + | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS + | Context.BIND_NOT_APP_COMPONENT_USAGE); } else if (job.shouldTreatAsExpeditedJob()) { - bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND - | Context.BIND_ALMOST_PERCEPTIBLE - | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS - | Context.BIND_NOT_APP_COMPONENT_USAGE; + bindFlags = Context.BindServiceFlags.of( + Context.BIND_AUTO_CREATE + | Context.BIND_NOT_FOREGROUND + | Context.BIND_ALMOST_PERCEPTIBLE + | Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS + | Context.BIND_NOT_APP_COMPONENT_USAGE); } else { - bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND - | Context.BIND_NOT_PERCEPTIBLE - | Context.BIND_NOT_APP_COMPONENT_USAGE; + bindFlags = Context.BindServiceFlags.of( + Context.BIND_AUTO_CREATE + | Context.BIND_NOT_FOREGROUND + | Context.BIND_NOT_PERCEPTIBLE + | Context.BIND_NOT_APP_COMPONENT_USAGE); } binding = mContext.bindServiceAsUser(intent, this, bindFlags, UserHandle.of(job.getUserId())); @@ -504,6 +511,37 @@ public final class JobServiceContext implements ServiceConnection { } } + private boolean canGetNetworkInformation(@NonNull JobStatus job) { + if (job.getJob().getRequiredNetwork() == null) { + // The job never had a network constraint, so we're not going to give it a network + // object. Add this check as an early return to avoid wasting cycles doing permission + // checks for this job. + return false; + } + // The calling app is doing the work, so use its UID, not the source UID. + final int uid = job.getUid(); + if (CompatChanges.isChangeEnabled( + JobSchedulerService.REQUIRE_NETWORK_PERMISSIONS_FOR_CONNECTIVITY_JOBS, uid)) { + final String pkgName = job.getServiceComponent().getPackageName(); + if (!hasPermissionForDelivery(uid, pkgName, Manifest.permission.INTERNET)) { + return false; + } + if (!hasPermissionForDelivery(uid, pkgName, Manifest.permission.ACCESS_NETWORK_STATE)) { + return false; + } + } + + return true; + } + + private boolean hasPermissionForDelivery(int uid, @NonNull String pkgName, + @NonNull String permission) { + final int result = PermissionChecker.checkPermissionForDataDelivery(mContext, permission, + PermissionChecker.PID_UNKNOWN, uid, pkgName, /* attributionTag */ null, + "network info via JS"); + return result == PermissionChecker.PERMISSION_GRANTED; + } + @EconomicPolicy.AppAction private static int getStartActionId(@NonNull JobStatus job) { switch (job.getEffectivePriority()) { @@ -603,6 +641,15 @@ public final class JobServiceContext implements ServiceConnection { } void informOfNetworkChangeLocked(Network newNetwork) { + if (newNetwork != null && mRunningJob != null && !canGetNetworkInformation(mRunningJob)) { + // The app can't get network information, so there's no point informing it of network + // changes. This case may happen if an app had scheduled network job and then + // started targeting U+ without requesting the required network permissions. + if (DEBUG) { + Slog.d(TAG, "Skipping network change call because of missing permissions"); + } + return; + } if (mVerb != VERB_EXECUTING) { Slog.w(TAG, "Sending onNetworkChanged for a job that isn't started. " + mRunningJob); if (mVerb == VERB_BINDING || mVerb == VERB_STARTING) { diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java index 4c55dac626d5..5246f2bf838b 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java @@ -188,7 +188,7 @@ public final class BatteryController extends RestrictingController { mLastReportedStatsdStablePower = stablePower; } if (mLastReportedStatsdBatteryNotLow == null - || mLastReportedStatsdBatteryNotLow != stablePower) { + || mLastReportedStatsdBatteryNotLow != batteryNotLow) { logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_BATTERY_NOT_LOW, batteryNotLow); mLastReportedStatsdBatteryNotLow = batteryNotLow; diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index 3859d89c22cd..f6bdb9303a04 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -18,15 +18,18 @@ package com.android.server.job.controllers; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.job.JobInfo; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.INetworkPolicyListener; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkPolicyManager; @@ -47,6 +50,7 @@ import android.util.Log; import android.util.Pools; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -98,13 +102,12 @@ public final class ConnectivityController extends RestrictingController implemen ~(ConnectivityManager.BLOCKED_REASON_APP_STANDBY | ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER | ConnectivityManager.BLOCKED_REASON_DOZE); - // TODO(261999509): allow bypassing data saver & user-restricted. However, when we allow a UI - // job to run while data saver restricts the app, we must ensure that we don't run regular - // jobs when we put a hole in the data saver wall for the UI job private static final int UNBYPASSABLE_UI_BLOCKED_REASONS = ~(ConnectivityManager.BLOCKED_REASON_APP_STANDBY | ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER - | ConnectivityManager.BLOCKED_REASON_DOZE); + | ConnectivityManager.BLOCKED_REASON_DOZE + | ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER + | ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED); private static final int UNBYPASSABLE_FOREGROUND_BLOCKED_REASONS = ~(ConnectivityManager.BLOCKED_REASON_APP_STANDBY | ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER @@ -113,6 +116,7 @@ public final class ConnectivityController extends RestrictingController implemen | ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED); private final ConnectivityManager mConnManager; + private final NetworkPolicyManager mNetPolicyManager; private final NetworkPolicyManagerInternal mNetPolicyManagerInternal; private final FlexibilityController mFlexibilityController; @@ -241,6 +245,8 @@ public final class ConnectivityController extends RestrictingController implemen */ private final List<UidStats> mSortedStats = new ArrayList<>(); @GuardedBy("mLock") + private final SparseBooleanArray mBackgroundMeteredAllowed = new SparseBooleanArray(); + @GuardedBy("mLock") private long mLastCallbackAdjustmentTimeElapsed; @GuardedBy("mLock") private final SparseArray<CellSignalStrengthCallback> mSignalStrengths = new SparseArray<>(); @@ -250,6 +256,8 @@ public final class ConnectivityController extends RestrictingController implemen private static final int MSG_ADJUST_CALLBACKS = 0; private static final int MSG_UPDATE_ALL_TRACKED_JOBS = 1; + private static final int MSG_DATA_SAVER_TOGGLED = 2; + private static final int MSG_UID_POLICIES_CHANGED = 3; private final Handler mHandler; @@ -259,6 +267,7 @@ public final class ConnectivityController extends RestrictingController implemen mHandler = new CcHandler(AppSchedulingModuleThread.get().getLooper()); mConnManager = mContext.getSystemService(ConnectivityManager.class); + mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); mNetPolicyManagerInternal = LocalServices.getService(NetworkPolicyManagerInternal.class); mFlexibilityController = flexibilityController; @@ -266,6 +275,8 @@ public final class ConnectivityController extends RestrictingController implemen // network changes against the active network for each UID with jobs. final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); mConnManager.registerNetworkCallback(request, mNetworkCallback); + + mNetPolicyManager.registerListener(mNetPolicyListener); } @GuardedBy("mLock") @@ -530,6 +541,7 @@ public final class ConnectivityController extends RestrictingController implemen // All packages in the UID have been removed. It's safe to remove things based on // UID alone. mTrackedJobs.delete(uid); + mBackgroundMeteredAllowed.delete(uid); UidStats uidStats = mUidStats.removeReturnOld(uid); unregisterDefaultNetworkCallbackLocked(uid, sElapsedRealtimeClock.millis()); mSortedStats.remove(uidStats); @@ -549,6 +561,12 @@ public final class ConnectivityController extends RestrictingController implemen mUidStats.removeAt(u); } } + for (int u = mBackgroundMeteredAllowed.size() - 1; u >= 0; --u) { + final int uid = mBackgroundMeteredAllowed.keyAt(u); + if (UserHandle.getUserId(uid) == userId) { + mBackgroundMeteredAllowed.removeAt(u); + } + } postAdjustCallbacks(); } @@ -666,6 +684,88 @@ public final class ConnectivityController extends RestrictingController implemen return false; } + private boolean isMeteredAllowed(@NonNull JobStatus jobStatus, + @NonNull NetworkCapabilities networkCapabilities) { + // Network isn't metered. Usage is allowed. The rest of this method doesn't apply. + if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) + || networkCapabilities.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)) { + return true; + } + + final int uid = jobStatus.getSourceUid(); + final int procState = mService.getUidProcState(uid); + final int capabilities = mService.getUidCapabilities(uid); + // Jobs don't raise the proc state to anything better than IMPORTANT_FOREGROUND. + // If the app is in a better state, see if it has the capability to use the metered network. + final boolean currentStateAllows = procState != ActivityManager.PROCESS_STATE_UNKNOWN + && procState < ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + && NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground( + procState, capabilities); + if (DEBUG) { + Slog.d(TAG, "UID " + uid + + " current state allows metered network=" + currentStateAllows + + " procState=" + ActivityManager.procStateToString(procState) + + " capabilities=" + ActivityManager.getCapabilitiesSummary(capabilities)); + } + if (currentStateAllows) { + return true; + } + + if ((jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) { + final int expectedProcState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; + final int mergedCapabilities = capabilities + | NetworkPolicyManager.getDefaultProcessNetworkCapabilities(expectedProcState); + final boolean wouldBeAllowed = + NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground( + expectedProcState, mergedCapabilities); + if (DEBUG) { + Slog.d(TAG, "UID " + uid + + " willBeForeground flag allows metered network=" + wouldBeAllowed + + " capabilities=" + + ActivityManager.getCapabilitiesSummary(mergedCapabilities)); + } + if (wouldBeAllowed) { + return true; + } + } + + if (jobStatus.shouldTreatAsUserInitiatedJob()) { + // Since the job is initiated by the user and will be visible to the user, it + // should be able to run on metered networks, similar to FGS. + // With user-initiated jobs, JobScheduler will request that the process + // run at IMPORTANT_FOREGROUND process state + // and get the USER_RESTRICTED_NETWORK process capability. + final int expectedProcState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; + final int mergedCapabilities = capabilities + | ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK + | NetworkPolicyManager.getDefaultProcessNetworkCapabilities(expectedProcState); + final boolean wouldBeAllowed = + NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground( + expectedProcState, mergedCapabilities); + if (DEBUG) { + Slog.d(TAG, "UID " + uid + + " UI job state allows metered network=" + wouldBeAllowed + + " capabilities=" + mergedCapabilities); + } + if (wouldBeAllowed) { + return true; + } + } + + if (mBackgroundMeteredAllowed.indexOfKey(uid) >= 0) { + return mBackgroundMeteredAllowed.get(uid); + } + + final boolean allowed = + mNetPolicyManager.getRestrictBackgroundStatus(uid) + != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; + if (DEBUG) { + Slog.d(TAG, "UID " + uid + " allowed in data saver=" + allowed); + } + mBackgroundMeteredAllowed.put(uid, allowed); + return allowed; + } + /** * Return the estimated amount of time this job will be transferring data, * based on the current network speed. @@ -859,6 +959,12 @@ public final class ConnectivityController extends RestrictingController implemen // First, are we insane? if (isInsane(jobStatus, network, capabilities, constants)) return false; + // User-initiated jobs might make NetworkPolicyManager open up network access for + // the whole UID. If network access is opened up just because of UI jobs, we want + // to make sure that non-UI jobs don't run during that time, + // so make sure the job can make use of the metered network at this time. + if (!isMeteredAllowed(jobStatus, capabilities)) return false; + // Second, is the network congested? if (isCongestionDelayed(jobStatus, network, capabilities, constants)) return false; @@ -1138,9 +1244,10 @@ public final class ConnectivityController extends RestrictingController implemen // but it doesn't yet satisfy the requested constraints and the old network // is still available and satisfies the constraints. Don't change the network // given to the job for now and let it keep running. We will re-evaluate when - // the capabilities or connection state of the either network change. + // the capabilities or connection state of either network change. if (DEBUG) { - Slog.i(TAG, "Not reassigning network for running job " + jobStatus); + Slog.i(TAG, "Not reassigning network from " + jobStatus.network + + " to " + network + " for running job " + jobStatus); } return false; } @@ -1389,6 +1496,26 @@ public final class ConnectivityController extends RestrictingController implemen } }; + private final INetworkPolicyListener mNetPolicyListener = new NetworkPolicyManager.Listener() { + @Override + public void onRestrictBackgroundChanged(boolean restrictBackground) { + if (DEBUG) { + Slog.v(TAG, "onRestrictBackgroundChanged: " + restrictBackground); + } + mHandler.obtainMessage(MSG_DATA_SAVER_TOGGLED).sendToTarget(); + } + + @Override + public void onUidPoliciesChanged(int uid, int uidPolicies) { + if (DEBUG) { + Slog.v(TAG, "onUidPoliciesChanged: " + uid); + } + mHandler.obtainMessage(MSG_UID_POLICIES_CHANGED, + uid, mNetPolicyManager.getRestrictBackgroundStatus(uid)) + .sendToTarget(); + } + }; + private class CcHandler extends Handler { CcHandler(Looper looper) { super(looper); @@ -1410,6 +1537,27 @@ public final class ConnectivityController extends RestrictingController implemen updateAllTrackedJobsLocked(allowThrottle); } break; + + case MSG_DATA_SAVER_TOGGLED: + removeMessages(MSG_DATA_SAVER_TOGGLED); + synchronized (mLock) { + mBackgroundMeteredAllowed.clear(); + updateTrackedJobsLocked(-1, null); + } + break; + + case MSG_UID_POLICIES_CHANGED: + final int uid = msg.arg1; + final boolean newAllowed = + msg.arg2 != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; + synchronized (mLock) { + final boolean oldAllowed = mBackgroundMeteredAllowed.get(uid); + if (oldAllowed != newAllowed) { + mBackgroundMeteredAllowed.put(uid, newAllowed); + updateTrackedJobsLocked(uid, null); + } + } + break; } } } 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 26d6ba254f8a..7cc2f28a5664 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 @@ -1131,10 +1131,25 @@ public final class JobStatus { */ @JobInfo.Priority public int getEffectivePriority() { - final int rawPriority = job.getPriority(); + final boolean isDemoted = + (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_USER) != 0 + || (job.isUserInitiated() + && (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ) != 0); + final int maxPriority; + if (isDemoted) { + // If the job was demoted for some reason, limit its priority to HIGH. + maxPriority = JobInfo.PRIORITY_HIGH; + } else { + maxPriority = JobInfo.PRIORITY_MAX; + } + final int rawPriority = Math.min(maxPriority, job.getPriority()); if (numFailures < 2) { return rawPriority; } + if (shouldTreatAsUserInitiatedJob()) { + // Don't drop priority of UI jobs. + return rawPriority; + } // Slowly decay priority of jobs to prevent starvation of other jobs. if (isRequestedExpeditedJob()) { // EJs can't fall below HIGH priority. diff --git a/cmds/gpu_counter_producer/Android.bp b/cmds/gpu_counter_producer/Android.bp new file mode 100644 index 000000000000..5b118ce62679 --- /dev/null +++ b/cmds/gpu_counter_producer/Android.bp @@ -0,0 +1,26 @@ +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["frameworks_base_license"], +} + +cc_binary { + name: "gpu_counter_producer", + + srcs: ["main.cpp"], + + shared_libs: [ + "libdl", + "liblog", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wunused", + "-Wunreachable-code", + "-fPIE", + "-pie", + ], + + soc_specific: true, +} diff --git a/cmds/gpu_counter_producer/OWNERS b/cmds/gpu_counter_producer/OWNERS new file mode 100644 index 000000000000..892c2fb81cde --- /dev/null +++ b/cmds/gpu_counter_producer/OWNERS @@ -0,0 +1 @@ +pmuetschard@google.com diff --git a/cmds/gpu_counter_producer/main.cpp b/cmds/gpu_counter_producer/main.cpp new file mode 100644 index 000000000000..1054cba74a6b --- /dev/null +++ b/cmds/gpu_counter_producer/main.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "gpu_counters" + +#include <dlfcn.h> +#include <fcntl.h> +#include <log/log.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define _LOG(level, msg, ...) \ + do { \ + fprintf(stderr, #level ": " msg "\n", ##__VA_ARGS__); \ + ALOG##level(msg, ##__VA_ARGS__); \ + } while (false) + +#define LOG_ERR(msg, ...) _LOG(E, msg, ##__VA_ARGS__) +#define LOG_WARN(msg, ...) _LOG(W, msg, ##__VA_ARGS__) +#define LOG_INFO(msg, ...) _LOG(I, msg, ##__VA_ARGS__) + +#define NELEM(x) (sizeof(x) / sizeof(x[0])) + +typedef void (*FN_PTR)(void); + +const char* kProducerPaths[] = { + "libgpudataproducer.so", +}; +const char* kPidFileName = "/data/local/tmp/gpu_counter_producer.pid"; + +static FN_PTR loadLibrary(const char* lib) { + char* error; + + LOG_INFO("Trying %s", lib); + void* handle = dlopen(lib, RTLD_GLOBAL); + if ((error = dlerror()) != nullptr || handle == nullptr) { + LOG_WARN("Error loading lib: %s", error); + return nullptr; + } + + FN_PTR startFunc = (FN_PTR)dlsym(handle, "start"); + if ((error = dlerror()) != nullptr) { + LOG_ERR("Error looking for start symbol: %s", error); + dlclose(handle); + return nullptr; + } + return startFunc; +} + +static void killExistingProcess() { + int fd = open(kPidFileName, O_RDONLY); + if (fd == -1) { + return; + } + char pidString[10]; + if (read(fd, pidString, 10) > 0) { + int pid = -1; + sscanf(pidString, "%d", &pid); + if (pid > 0) { + kill(pid, SIGINT); + } + } + close(fd); +} + +static bool writeToPidFile() { + killExistingProcess(); + int fd = open(kPidFileName, O_CREAT | O_WRONLY | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd == -1) { + return false; + } + pid_t pid = getpid(); + char pidString[10]; + sprintf(pidString, "%d", pid); + write(fd, pidString, strlen(pidString)); + close(fd); + return true; +} + +static void clearPidFile() { + unlink(kPidFileName); +} + +static void usage(const char* pname) { + fprintf(stderr, + "Starts the GPU hardware counter profiling Perfetto data producer.\n\n" + "usage: %s [-hf]\n" + " -f: run in the foreground.\n" + " -h: this message.\n", + pname); +} + +// Program to load the GPU Perfetto producer .so and call start(). +int main(int argc, char** argv) { + const char* pname = argv[0]; + bool foreground = false; + int c; + while ((c = getopt(argc, argv, "fh")) != -1) { + switch (c) { + case 'f': + foreground = true; + break; + case '?': + case ':': + case 'h': + usage(pname); + return 1; + } + } + + if (optind < argc) { + usage(pname); + return 1; + } + + if (!foreground) { + daemon(0, 0); + } + + if (!writeToPidFile()) { + LOG_ERR("Could not open %s", kPidFileName); + return 1; + } + + dlerror(); // Clear any possibly ignored previous error. + FN_PTR startFunc = nullptr; + for (int i = 0; startFunc == nullptr && i < NELEM(kProducerPaths); i++) { + startFunc = loadLibrary(kProducerPaths[i]); + } + + if (startFunc == nullptr) { + LOG_ERR("Did not find the producer library"); + LOG_ERR("LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH")); + clearPidFile(); + return 1; + } + + LOG_INFO("Calling start at %p", startFunc); + (*startFunc)(); + LOG_WARN("Producer has exited."); + + clearPidFile(); + return 0; +} diff --git a/core/api/current.txt b/core/api/current.txt index 4332d21b297c..80abd84733d7 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -64,8 +64,6 @@ package android { field public static final String BLUETOOTH_SCAN = "android.permission.BLUETOOTH_SCAN"; field public static final String BODY_SENSORS = "android.permission.BODY_SENSORS"; field public static final String BODY_SENSORS_BACKGROUND = "android.permission.BODY_SENSORS_BACKGROUND"; - field public static final String BODY_SENSORS_WRIST_TEMPERATURE = "android.permission.BODY_SENSORS_WRIST_TEMPERATURE"; - field public static final String BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND = "android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND"; field public static final String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED"; field public static final String BROADCAST_SMS = "android.permission.BROADCAST_SMS"; field public static final String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY"; @@ -4507,7 +4505,6 @@ package android.app { method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int); method public final void runOnUiThread(Runnable); method public void setActionBar(@Nullable android.widget.Toolbar); - method public void setAllowCrossUidActivitySwitchFromBelow(boolean); method public void setContentTransitionManager(android.transition.TransitionManager); method public void setContentView(@LayoutRes int); method public void setContentView(android.view.View); @@ -5025,7 +5022,6 @@ package android.app { field public static final String OPSTR_ADD_VOICEMAIL = "android:add_voicemail"; field public static final String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls"; field public static final String OPSTR_BODY_SENSORS = "android:body_sensors"; - field public static final String OPSTR_BODY_SENSORS_WRIST_TEMPERATURE = "android:body_sensors_wrist_temperature"; field public static final String OPSTR_CALL_PHONE = "android:call_phone"; field public static final String OPSTR_CAMERA = "android:camera"; field public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -13030,7 +13026,7 @@ package android.content.pm { field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR, android.Manifest.permission.UWB_RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 - field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2 @@ -13645,10 +13641,10 @@ package android.credentials { } public final class CredentialDescription implements android.os.Parcelable { - ctor public CredentialDescription(@NonNull String, @NonNull String, @NonNull java.util.List<android.service.credentials.CredentialEntry>); + ctor public CredentialDescription(@NonNull String, @NonNull java.util.Set<java.lang.String>, @NonNull java.util.List<android.service.credentials.CredentialEntry>); method public int describeContents(); method @NonNull public java.util.List<android.service.credentials.CredentialEntry> getCredentialEntries(); - method @NonNull public String getFlattenedRequestString(); + method @NonNull public java.util.Set<java.lang.String> getSupportedElementKeys(); method @NonNull public String getType(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CredentialDescription> CREATOR; @@ -13656,9 +13652,9 @@ package android.credentials { public final class CredentialManager { method public void clearCredentialState(@NonNull android.credentials.ClearCredentialStateRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException>); - method public void createCredential(@NonNull android.credentials.CreateCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.CreateCredentialResponse,android.credentials.CreateCredentialException>); - method public void getCredential(@NonNull android.credentials.GetCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>); - method public void getCredential(@NonNull android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>); + method public void createCredential(@NonNull android.content.Context, @NonNull android.credentials.CreateCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.CreateCredentialResponse,android.credentials.CreateCredentialException>); + method public void getCredential(@NonNull android.content.Context, @NonNull android.credentials.GetCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>); + method public void getCredential(@NonNull android.content.Context, @NonNull android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>); method public boolean isEnabledCredentialProviderService(@NonNull android.content.ComponentName); method public void prepareGetCredential(@NonNull android.credentials.GetCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.PrepareGetCredentialResponse,android.credentials.GetCredentialException>); method public void registerCredentialDescription(@NonNull android.credentials.RegisterCredentialDescriptionRequest); @@ -13675,7 +13671,7 @@ package android.credentials { method public boolean isSystemProviderRequired(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CredentialOption> CREATOR; - field public static final String FLATTENED_REQUEST = "android.credentials.GetCredentialOption.FLATTENED_REQUEST_STRING"; + field public static final String SUPPORTED_ELEMENT_KEYS = "android.credentials.GetCredentialOption.SUPPORTED_ELEMENT_KEYS"; } public static final class CredentialOption.Builder { @@ -19894,8 +19890,8 @@ package android.hardware.usb { method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int, int); method public boolean claimInterface(android.hardware.usb.UsbInterface, boolean); method public void close(); - method public int controlTransfer(int, int, int, int, byte[], int, int); - method public int controlTransfer(int, int, int, int, byte[], int, int, int); + method public int controlTransfer(int, int, int, int, @Nullable byte[], int, int); + method public int controlTransfer(int, int, int, int, @Nullable byte[], int, int, int); method public int getFileDescriptor(); method public byte[] getRawDescriptors(); method public String getSerial(); @@ -40720,7 +40716,6 @@ package android.service.credentials { method public abstract void onBeginGetCredential(@NonNull android.service.credentials.BeginGetCredentialRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,android.credentials.GetCredentialException>); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void onClearCredentialState(@NonNull android.service.credentials.ClearCredentialStateRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException>); - field @Deprecated public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities"; field public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST = "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST"; field public static final String EXTRA_BEGIN_GET_CREDENTIAL_RESPONSE = "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_RESPONSE"; field public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION = "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION"; @@ -43415,6 +43410,8 @@ package android.telephony { field public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array"; field public static final String KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL = "carrier_provisions_wifi_merged_networks_bool"; field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool"; + field public static final String KEY_CARRIER_SERVICE_NAME_STRING_ARRAY = "carrier_service_name_array"; + field public static final String KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY = "carrier_service_number_array"; field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool"; @@ -50903,6 +50900,10 @@ package android.view { field public static final int KEYCODE_LAST_CHANNEL = 229; // 0xe5 field public static final int KEYCODE_LEFT_BRACKET = 71; // 0x47 field public static final int KEYCODE_M = 41; // 0x29 + field public static final int KEYCODE_MACRO_1 = 313; // 0x139 + field public static final int KEYCODE_MACRO_2 = 314; // 0x13a + field public static final int KEYCODE_MACRO_3 = 315; // 0x13b + field public static final int KEYCODE_MACRO_4 = 316; // 0x13c field public static final int KEYCODE_MANNER_MODE = 205; // 0xcd field public static final int KEYCODE_MEDIA_AUDIO_TRACK = 222; // 0xde field public static final int KEYCODE_MEDIA_CLOSE = 128; // 0x80 @@ -55062,7 +55063,6 @@ package android.view.autofill { public final class AutofillManager { method public void cancel(); - method public void clearAutofillRequestCallback(); method public void commit(); method public void disableAutofillServices(); method @Nullable public android.content.ComponentName getAutofillServiceComponentName(); @@ -55089,7 +55089,6 @@ package android.view.autofill { method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback); method public void requestAutofill(@NonNull android.view.View); method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect); - method @RequiresPermission(android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS) public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback); method public void setUserData(@Nullable android.service.autofill.UserData); method public boolean showAutofillDialog(@NonNull android.view.View); method public boolean showAutofillDialog(@NonNull android.view.View, int); @@ -55110,10 +55109,6 @@ package android.view.autofill { field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } - public interface AutofillRequestCallback { - method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback); - } - public final class AutofillValue implements android.os.Parcelable { method public int describeContents(); method public static android.view.autofill.AutofillValue forDate(long); @@ -55563,12 +55558,10 @@ package android.view.inputmethod { ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>); method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addInlinePresentationSpecs(@NonNull android.widget.inline.InlinePresentationSpec); method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build(); - method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean); method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setExtras(@NonNull android.os.Bundle); method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>); method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlineTooltipPresentationSpec(@NonNull android.widget.inline.InlinePresentationSpec); method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int); - method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean); method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setSupportedLocales(@NonNull android.os.LocaleList); } @@ -60399,6 +60392,7 @@ package android.widget { method public void setLineBreakStyle(int); method public void setLineBreakWordStyle(int); method public void setLineHeight(@IntRange(from=0) @Px int); + method public void setLineHeight(int, @FloatRange(from=0) float); method public void setLineSpacing(float, float); method public void setLines(int); method public final void setLinkTextColor(@ColorInt int); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 58f78aa4fc15..c1f6219025f9 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -18,6 +18,7 @@ package android.app { public class ActivityManager { method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener); + method @NonNull @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int[] getUidFrozenState(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void registerUidFrozenStateChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.ActivityManager.UidFrozenStateChangedCallback); method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener); method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void unregisterUidFrozenStateChangedCallback(@NonNull android.app.ActivityManager.UidFrozenStateChangedCallback); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index b21028464426..fbc69e34a644 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -33,7 +33,6 @@ package android { field public static final String ADD_TRUSTED_DISPLAY = "android.permission.ADD_TRUSTED_DISPLAY"; field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"; field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE"; - field public static final String ALLOWLISTED_WRITE_DEVICE_CONFIG = "android.permission.ALLOWLISTED_WRITE_DEVICE_CONFIG"; field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"; field public static final String ALLOW_PLACE_IN_MULTI_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS"; field public static final String ALLOW_SLIPPERY_TOUCHES = "android.permission.ALLOW_SLIPPERY_TOUCHES"; @@ -380,6 +379,7 @@ package android { field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"; field public static final String WIFI_UPDATE_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS"; field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"; + field public static final String WRITE_ALLOWLISTED_DEVICE_CONFIG = "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG"; field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG"; field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE"; field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 7107bf7419e5..1346d0761b20 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -5,10 +5,11 @@ package android { field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS"; field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"; - field public static final String ALLOWLISTED_WRITE_DEVICE_CONFIG = "android.permission.ALLOWLISTED_WRITE_DEVICE_CONFIG"; field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS"; field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA"; field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE"; + field public static final String BODY_SENSORS_WRIST_TEMPERATURE = "android.permission.BODY_SENSORS_WRIST_TEMPERATURE"; + field public static final String BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND = "android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND"; field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"; field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE"; @@ -55,6 +56,7 @@ package android { field public static final String TEST_INPUT_METHOD = "android.permission.TEST_INPUT_METHOD"; field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS"; field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS"; + field public static final String WRITE_ALLOWLISTED_DEVICE_CONFIG = "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG"; field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG"; field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE"; field public static final String WRITE_OBB = "android.permission.WRITE_OBB"; @@ -131,11 +133,13 @@ package android.app { method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public int[] getDisplayIdsForStartingVisibleBackgroundUsers(); method public long getTotalRam(); + method @NonNull @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int[] getUidFrozenState(@NonNull int[]); method @RequiresPermission(allOf={android.Manifest.permission.PACKAGE_USAGE_STATS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public int getUidProcessCapabilities(int); method @RequiresPermission(allOf={android.Manifest.permission.PACKAGE_USAGE_STATS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public int getUidProcessState(int); method public void holdLock(android.os.IBinder, int); method public static boolean isHighEndGfx(); method public void notifySystemPropertiesChanged(); + method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void registerUidFrozenStateChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.ActivityManager.UidFrozenStateChangedCallback); method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener); method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors(); method public static void resumeAppSwitches() throws android.os.RemoteException; @@ -143,12 +147,13 @@ package android.app { method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void setStopUserOnSwitch(int); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean startUserInBackgroundVisibleOnDisplay(int, int); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean); + method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void unregisterUidFrozenStateChangedCallback(@NonNull android.app.ActivityManager.UidFrozenStateChangedCallback); method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle(); field public static final long LOCK_DOWN_CLOSE_SYSTEM_DIALOGS = 174664365L; // 0xa692aadL field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6 - field @Deprecated public static final int PROCESS_CAPABILITY_NETWORK = 8; // 0x8 field public static final int PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK = 8; // 0x8 + field public static final int PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK = 32; // 0x20 field public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; // 0x4 field public static final int PROCESS_STATE_TOP = 2; // 0x2 field public static final int STOP_USER_ON_SWITCH_DEFAULT = -1; // 0xffffffff @@ -166,6 +171,12 @@ package android.app { method @Nullable public String getIconResourcePackage(); } + public static interface ActivityManager.UidFrozenStateChangedCallback { + method public void onUidFrozenStateChanged(@NonNull int[], @NonNull int[]); + field public static final int UID_FROZEN_STATE_FROZEN = 1; // 0x1 + field public static final int UID_FROZEN_STATE_UNFROZEN = 2; // 0x2 + } + public class ActivityOptions extends android.app.ComponentOptions { method public boolean isEligibleForLegacyPermissionPrompt(); method @NonNull public static android.app.ActivityOptions makeCustomAnimation(@NonNull android.content.Context, int, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); @@ -415,6 +426,7 @@ package android.app { method public void clickNotification(@Nullable String, int, int, boolean); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void collapsePanels(); method public void expandNotificationsPanel(); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public int getLastSystemKey(); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void handleSystemKey(int); method public void sendNotificationFeedback(@Nullable String, @Nullable android.os.Bundle); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean); @@ -914,6 +926,12 @@ package android.content.pm { field public static final long FORCE_NON_RESIZE_APP = 181136395L; // 0xacbec0bL field public static final long FORCE_RESIZE_APP = 174042936L; // 0xa5faf38L field public static final long NEVER_SANDBOX_DISPLAY_APIS = 184838306L; // 0xb0468a2L + field public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION = 263959004L; // 0xfbbb1dcL + field public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH = 264304459L; // 0xfc0f74bL + field public static final long OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE = 264301586L; // 0xfc0ec12L + field public static final long OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS = 263259275L; // 0xfb1048bL + field public static final long OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION = 254631730L; // 0xf2d5f32L + field public static final long OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE = 266124927L; // 0xfdcbe7fL field public static final long OVERRIDE_MIN_ASPECT_RATIO = 174042980L; // 0xa5faf64L field public static final long OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN = 218959984L; // 0xd0d1070L field public static final long OVERRIDE_MIN_ASPECT_RATIO_LARGE = 180326787L; // 0xabf9183L @@ -923,6 +941,9 @@ package android.content.pm { field public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // 0xc2368d6L field public static final long OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN = 208648326L; // 0xc6fb886L field public static final long OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS = 237531167L; // 0xe28701fL + field public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR = 265451093L; // 0xfd27655L + field public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT = 265452344L; // 0xfd27b38L + field public static final long OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION = 255940284L; // 0xf4156bcL field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2 } @@ -2597,7 +2618,6 @@ package android.provider { field @Deprecated public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices"; field public static final String SHOW_FIRST_CRASH_DIALOG = "show_first_crash_dialog"; - field public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled"; field public static final String USER_DISABLED_HDR_FORMATS = "user_disabled_hdr_formats"; field public static final String USER_PREFERRED_REFRESH_RATE = "user_preferred_refresh_rate"; field public static final String USER_PREFERRED_RESOLUTION_HEIGHT = "user_preferred_resolution_height"; @@ -2628,6 +2648,9 @@ package android.provider { field public static final String SELECTED_SPELL_CHECKER_SUBTYPE = "selected_spell_checker_subtype"; field public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION = "show_first_crash_dialog_dev_option"; field public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard"; + field public static final String STYLUS_BUTTONS_ENABLED = "stylus_buttons_enabled"; + field public static final int STYLUS_HANDWRITING_DEFAULT_VALUE = 1; // 0x1 + field public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled"; field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service"; } @@ -3330,7 +3353,7 @@ package android.view { method public static String actionToString(int); method public final void setDisplayId(int); field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800 - field public static final int LAST_KEYCODE = 312; // 0x138 + field public static final int LAST_KEYCODE = 316; // 0x13c } public final class KeyboardShortcutGroup implements android.os.Parcelable { @@ -3499,12 +3522,18 @@ package android.view.autofill { } public final class AutofillManager { + method public void clearAutofillRequestCallback(); + method @RequiresPermission(android.Manifest.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS) public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback); field public static final String ANY_HINT = "any"; field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0 field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1 field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0 } + public interface AutofillRequestCallback { + method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback); + } + } package android.view.contentcapture { @@ -3628,6 +3657,11 @@ package android.view.inputmethod { method @NonNull public static android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(@NonNull android.widget.inline.InlinePresentationSpec, @NonNull String, @Nullable String[], @NonNull String, boolean); } + public static final class InlineSuggestionsRequest.Builder { + method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean); + method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean); + } + public final class InlineSuggestionsResponse implements android.os.Parcelable { method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>); } diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 4a972806b314..cf0264353159 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -183,6 +183,10 @@ MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setShoul android.telecom.ConnectionRequest does not declare a `shouldShowIncomingCallUi()` method matching method android.telecom.ConnectionRequest.Builder.setShouldShowIncomingCallUi(boolean) MissingGetterMatchingBuilder: android.view.Display.Mode.Builder#setResolution(int, int): android.view.Display.Mode does not declare a `getResolution()` method matching method android.view.Display.Mode.Builder.setResolution(int,int) +MissingGetterMatchingBuilder: android.view.inputmethod.InlineSuggestionsRequest.Builder#setClientSupported(boolean): + android.view.inputmethod.InlineSuggestionsRequest does not declare a `isClientSupported()` method matching method android.view.inputmethod.InlineSuggestionsRequest.Builder.setClientSupported(boolean) +MissingGetterMatchingBuilder: android.view.inputmethod.InlineSuggestionsRequest.Builder#setServiceSupported(boolean): + android.view.inputmethod.InlineSuggestionsRequest does not declare a `isServiceSupported()` method matching method android.view.inputmethod.InlineSuggestionsRequest.Builder.setServiceSupported(boolean) MissingNullability: android.app.Activity#onMovedToDisplay(int, android.content.res.Configuration) parameter #1: diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 5d69f8b80799..ead238f75ba4 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1118,10 +1118,6 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio if (Looper.myLooper() == null) { throw new AndroidRuntimeException("Animators may only be run on Looper threads"); } - if (playBackwards == mResumed && mSelfPulse == !mSuppressSelfPulseRequested && mStarted) { - // already started - return; - } mReversing = playBackwards; mSelfPulse = !mSuppressSelfPulseRequested; // Special case: reversing from seek-to-0 should act as if not seeked at all. diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 125e7270b0e2..8021ce0dc20d 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -9209,6 +9209,7 @@ public class Activity extends ContextThemeWrapper * * @param allowed {@code true} to disable the UID restrictions; {@code false} to revert back to * the default behaviour + * @hide */ public void setAllowCrossUidActivitySwitchFromBelow(boolean allowed) { ActivityClient.getInstance().setAllowCrossUidActivitySwitchFromBelow(mToken, allowed); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 929c07bc1dc5..813e32a81983 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -256,6 +256,7 @@ public class ActivityManager { * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi public interface UidFrozenStateChangedCallback { /** * Indicates that the UID was frozen. @@ -263,6 +264,7 @@ public class ActivityManager { * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi int UID_FROZEN_STATE_FROZEN = 1; /** @@ -271,6 +273,7 @@ public class ActivityManager { * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi int UID_FROZEN_STATE_UNFROZEN = 2; /** @@ -296,6 +299,7 @@ public class ActivityManager { * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi void onUidFrozenStateChanged(@NonNull int[] uids, @NonNull @UidFrozenState int[] frozenStates); } @@ -315,6 +319,7 @@ public class ActivityManager { */ @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi public void registerUidFrozenStateChangedCallback( @NonNull Executor executor, @NonNull UidFrozenStateChangedCallback callback) { @@ -346,6 +351,7 @@ public class ActivityManager { */ @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi public void unregisterUidFrozenStateChangedCallback( @NonNull UidFrozenStateChangedCallback callback) { Preconditions.checkNotNull(callback, "callback cannot be null"); @@ -363,6 +369,30 @@ public class ActivityManager { } /** + * Query the frozen state of a list of UIDs. + * + * @param uids the array of UIDs which the client would like to know the frozen state of. + * @return An array containing the frozen state for each requested UID, by index. Will be set + * to {@link UidFrozenStateChangedCallback#UID_FROZEN_STATE_FROZEN} + * if the UID is frozen. If the UID is not frozen or not found, + * {@link UidFrozenStateChangedCallback#UID_FROZEN_STATE_UNFROZEN} + * will be set. + * + * @hide + */ + @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi + public @NonNull @UidFrozenStateChangedCallback.UidFrozenState + int[] getUidFrozenState(@NonNull int[] uids) { + try { + return getService().getUidFrozenState(uids); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code * <meta-data>}</a> name for a 'home' Activity that declares a package that is to be * uninstalled in lieu of the declaring one. The package named here must be @@ -764,6 +794,7 @@ public class ActivityManager { PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK, PROCESS_CAPABILITY_BFSL, + PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK, }) @Retention(RetentionPolicy.SOURCE) public @interface ProcessCapability {} @@ -885,14 +916,6 @@ public class ActivityManager { /** @hide Process can access network despite any power saving restrictions */ @TestApi public static final int PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK = 1 << 3; - /** - * @hide - * @deprecated Use {@link #PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK} instead. - */ - @TestApi - @Deprecated - public static final int PROCESS_CAPABILITY_NETWORK = - PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; /** * Flag used to indicate whether an app is allowed to start a foreground service from the @@ -914,6 +937,13 @@ public class ActivityManager { public static final int PROCESS_CAPABILITY_BFSL = 1 << 4; /** + * @hide + * Process can access network at a high enough proc state despite any user restrictions. + */ + @TestApi + public static final int PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK = 1 << 5; + + /** * @hide all capabilities, the ORing of all flags in {@link ProcessCapability}. * * Don't expose it as TestApi -- we may add new capabilities any time, which could @@ -923,7 +953,8 @@ public class ActivityManager { | PROCESS_CAPABILITY_FOREGROUND_CAMERA | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK - | PROCESS_CAPABILITY_BFSL; + | PROCESS_CAPABILITY_BFSL + | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; /** * All implicit capabilities. There are capabilities that process automatically have. @@ -943,6 +974,7 @@ public class ActivityManager { pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-'); pw.print((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-'); pw.print((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-'); + pw.print((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-'); } /** @hide */ @@ -952,6 +984,7 @@ public class ActivityManager { sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-'); sb.append((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-'); sb.append((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-'); + sb.append((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-'); } /** diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index feb9b4f2664d..d73f0cca9a4e 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -2539,7 +2539,8 @@ public class ActivityOptions extends ComponentOptions { public String toString() { return "ActivityOptions(" + hashCode() + "), mPackageName=" + mPackageName + ", mAnimationType=" + mAnimationType + ", mStartX=" + mStartX + ", mStartY=" - + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight; + + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight + ", mLaunchDisplayId=" + + mLaunchDisplayId; } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 682fec8105d5..7b4aeeca2855 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -240,6 +240,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.net.InetAddress; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -359,9 +360,8 @@ public final class ActivityThread extends ClientTransactionHandler /** The activities to be truly destroyed (not include relaunch). */ final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed = Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>()); - // List of new activities (via ActivityRecord.nextIdle) that should - // be reported when next we idle. - ActivityClientRecord mNewActivities = null; + // List of new activities that should be reported when next we idle. + final ArrayList<ActivityClientRecord> mNewActivities = new ArrayList<>(); // Number of activities that are currently visible on-screen. @UnsupportedAppUsage int mNumVisibleActivities = 0; @@ -562,7 +562,6 @@ public final class ActivityThread extends ClientTransactionHandler private Configuration tmpConfig = new Configuration(); // Callback used for updating activity override config and camera compat control state. ViewRootImpl.ActivityConfigCallback activityConfigCallback; - ActivityClientRecord nextIdle; // Indicates whether this activity is currently the topmost resumed one in the system. // This holds the last reported value from server. @@ -656,7 +655,6 @@ public final class ActivityThread extends ClientTransactionHandler paused = false; stopped = false; hideForNow = false; - nextIdle = null; activityConfigCallback = new ViewRootImpl.ActivityConfigCallback() { @Override public void onConfigurationChanged(Configuration overrideConfig, @@ -2482,29 +2480,22 @@ public final class ActivityThread extends ClientTransactionHandler private class Idler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { - ActivityClientRecord a = mNewActivities; boolean stopProfiling = false; if (mBoundApplication != null && mProfiler.profileFd != null && mProfiler.autoStopProfiler) { stopProfiling = true; } - if (a != null) { - mNewActivities = null; - final ActivityClient ac = ActivityClient.getInstance(); - ActivityClientRecord prev; - do { - if (localLOGV) Slog.v( - TAG, "Reporting idle of " + a + - " finished=" + - (a.activity != null && a.activity.mFinished)); - if (a.activity != null && !a.activity.mFinished) { - ac.activityIdle(a.token, a.createdConfig, stopProfiling); - a.createdConfig = null; - } - prev = a; - a = a.nextIdle; - prev.nextIdle = null; - } while (a != null); + final ActivityClient ac = ActivityClient.getInstance(); + while (mNewActivities.size() > 0) { + final ActivityClientRecord a = mNewActivities.remove(0); + if (localLOGV) { + Slog.v(TAG, "Reporting idle of " + a + " finished=" + + (a.activity != null && a.activity.mFinished)); + } + if (a.activity != null && !a.activity.mFinished) { + ac.activityIdle(a.token, a.createdConfig, stopProfiling); + a.createdConfig = null; + } } if (stopProfiling) { mProfiler.stopProfiling(); @@ -4352,18 +4343,20 @@ public final class ActivityThread extends ClientTransactionHandler static void handleAttachStartupAgents(String dataDir) { try { - Path code_cache = ContextImpl.getCodeCacheDirBeforeBind(new File(dataDir)).toPath(); - if (!Files.exists(code_cache)) { + Path codeCache = ContextImpl.getCodeCacheDirBeforeBind(new File(dataDir)).toPath(); + if (!Files.exists(codeCache)) { return; } - Path startup_path = code_cache.resolve("startup_agents"); - if (Files.exists(startup_path)) { - for (Path p : Files.newDirectoryStream(startup_path)) { - handleAttachAgent( - p.toAbsolutePath().toString() - + "=" - + dataDir, - null); + Path startupPath = codeCache.resolve("startup_agents"); + if (Files.exists(startupPath)) { + try (DirectoryStream<Path> startupFiles = Files.newDirectoryStream(startupPath)) { + for (Path p : startupFiles) { + handleAttachAgent( + p.toAbsolutePath().toString() + + "=" + + dataDir, + null); + } } } } catch (Exception e) { @@ -5104,8 +5097,7 @@ public final class ActivityThread extends ClientTransactionHandler } } - r.nextIdle = mNewActivities; - mNewActivities = r; + mNewActivities.add(r); if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(new Idler()); } @@ -5706,6 +5698,7 @@ public final class ActivityThread extends ClientTransactionHandler } if (finishing) { ActivityClient.getInstance().activityDestroyed(r.token); + mNewActivities.remove(r); } mSomeActivitiesChanged = true; } @@ -5926,7 +5919,6 @@ public final class ActivityThread extends ClientTransactionHandler r.activity = null; r.window = null; r.hideForNow = false; - r.nextIdle = null; // Merge any pending results and pending intents; don't just replace them if (pendingResults != null) { if (r.pendingResults == null) { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 265b56418d4b..b48a8fb73832 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2188,7 +2188,10 @@ public class AppOpsManager { public static final String OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD = "android:capture_consentless_bugreport_on_userdebug_build"; - /** Access to wrist temperature body sensors. */ + /** + * Access to wrist temperature body sensors. + * @hide + */ public static final String OPSTR_BODY_SENSORS_WRIST_TEMPERATURE = "android:body_sensors_wrist_temperature"; diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 53b16d3a8170..9cd99dca1ab1 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -157,15 +157,15 @@ public class ApplicationLoaders { * All libraries in the closure of libraries to be loaded must be in libs. A library can * only depend on libraries that come before it in the list. */ - public void createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs) { + public void createAndCacheNonBootclasspathSystemClassLoaders(List<SharedLibraryInfo> libs) { if (mSystemLibsCacheMap != null) { throw new IllegalStateException("Already cached."); } - mSystemLibsCacheMap = new HashMap<String, CachedClassLoader>(); + mSystemLibsCacheMap = new HashMap<>(); - for (SharedLibraryInfo lib : libs) { - createAndCacheNonBootclasspathSystemClassLoader(lib); + for (int i = 0; i < libs.size(); i++) { + createAndCacheNonBootclasspathSystemClassLoader(libs.get(i)); } } diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index d23d3cd87fdb..6357798a6cab 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -37,8 +37,6 @@ import android.os.PowerExemptionManager; import android.os.PowerExemptionManager.ReasonCode; import android.os.PowerExemptionManager.TempAllowListType; -import com.android.internal.util.Preconditions; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -61,7 +59,8 @@ public class BroadcastOptions extends ComponentOptions { private long mRequireCompatChangeId = CHANGE_INVALID; private long mIdForResponseEvent; private @DeliveryGroupPolicy int mDeliveryGroupPolicy; - private @Nullable String mDeliveryGroupMatchingKey; + private @Nullable String mDeliveryGroupMatchingNamespaceFragment; + private @Nullable String mDeliveryGroupMatchingKeyFragment; private @Nullable BundleMerger mDeliveryGroupExtrasMerger; private @Nullable IntentFilter mDeliveryGroupMatchingFilter; private @DeferralPolicy int mDeferralPolicy; @@ -196,7 +195,13 @@ public class BroadcastOptions extends ComponentOptions { "android:broadcast.deliveryGroupPolicy"; /** - * Corresponds to {@link #setDeliveryGroupMatchingKey(String, String)}. + * Corresponds to namespace fragment of {@link #setDeliveryGroupMatchingKey(String, String)}. + */ + private static final String KEY_DELIVERY_GROUP_NAMESPACE = + "android:broadcast.deliveryGroupMatchingNamespace"; + + /** + * Corresponds to key fragment of {@link #setDeliveryGroupMatchingKey(String, String)}. */ private static final String KEY_DELIVERY_GROUP_KEY = "android:broadcast.deliveryGroupMatchingKey"; @@ -337,7 +342,8 @@ public class BroadcastOptions extends ComponentOptions { mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT); mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY, DELIVERY_GROUP_POLICY_ALL); - mDeliveryGroupMatchingKey = opts.getString(KEY_DELIVERY_GROUP_KEY); + mDeliveryGroupMatchingNamespaceFragment = opts.getString(KEY_DELIVERY_GROUP_NAMESPACE); + mDeliveryGroupMatchingKeyFragment = opts.getString(KEY_DELIVERY_GROUP_KEY); mDeliveryGroupExtrasMerger = opts.getParcelable(KEY_DELIVERY_GROUP_EXTRAS_MERGER, BundleMerger.class); mDeliveryGroupMatchingFilter = opts.getParcelable(KEY_DELIVERY_GROUP_MATCHING_FILTER, @@ -851,11 +857,8 @@ public class BroadcastOptions extends ComponentOptions { @NonNull public BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String namespace, @NonNull String key) { - Preconditions.checkArgument(!namespace.contains(":"), - "namespace should not contain ':'"); - Preconditions.checkArgument(!key.contains(":"), - "key should not contain ':'"); - mDeliveryGroupMatchingKey = namespace + ":" + key; + mDeliveryGroupMatchingNamespaceFragment = Objects.requireNonNull(namespace); + mDeliveryGroupMatchingKeyFragment = Objects.requireNonNull(key); return this; } @@ -868,7 +871,38 @@ public class BroadcastOptions extends ComponentOptions { */ @Nullable public String getDeliveryGroupMatchingKey() { - return mDeliveryGroupMatchingKey; + if (mDeliveryGroupMatchingNamespaceFragment == null + || mDeliveryGroupMatchingKeyFragment == null) { + return null; + } + return String.join(":", mDeliveryGroupMatchingNamespaceFragment, + mDeliveryGroupMatchingKeyFragment); + } + + /** + * Return the namespace fragment that is used to identify the delivery group that this + * broadcast belongs to. + * + * @return the delivery group namespace fragment that was previously set using + * {@link #setDeliveryGroupMatchingKey(String, String)}. + * @hide + */ + @Nullable + public String getDeliveryGroupMatchingNamespaceFragment() { + return mDeliveryGroupMatchingNamespaceFragment; + } + + /** + * Return the key fragment that is used to identify the delivery group that this + * broadcast belongs to. + * + * @return the delivery group key fragment that was previously set using + * {@link #setDeliveryGroupMatchingKey(String, String)}. + * @hide + */ + @Nullable + public String getDeliveryGroupMatchingKeyFragment() { + return mDeliveryGroupMatchingKeyFragment; } /** @@ -876,7 +910,8 @@ public class BroadcastOptions extends ComponentOptions { * {@link #setDeliveryGroupMatchingKey(String, String)}. */ public void clearDeliveryGroupMatchingKey() { - mDeliveryGroupMatchingKey = null; + mDeliveryGroupMatchingNamespaceFragment = null; + mDeliveryGroupMatchingKeyFragment = null; } /** @@ -1094,8 +1129,11 @@ public class BroadcastOptions extends ComponentOptions { if (mDeliveryGroupPolicy != DELIVERY_GROUP_POLICY_ALL) { b.putInt(KEY_DELIVERY_GROUP_POLICY, mDeliveryGroupPolicy); } - if (mDeliveryGroupMatchingKey != null) { - b.putString(KEY_DELIVERY_GROUP_KEY, mDeliveryGroupMatchingKey); + if (mDeliveryGroupMatchingNamespaceFragment != null) { + b.putString(KEY_DELIVERY_GROUP_NAMESPACE, mDeliveryGroupMatchingNamespaceFragment); + } + if (mDeliveryGroupMatchingKeyFragment != null) { + b.putString(KEY_DELIVERY_GROUP_KEY, mDeliveryGroupMatchingKeyFragment); } if (mDeliveryGroupPolicy == DELIVERY_GROUP_POLICY_MERGED) { if (mDeliveryGroupExtrasMerger != null) { diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 97d45623d3da..91eb4c44cda5 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -882,4 +882,6 @@ interface IActivityManager { void registerUidFrozenStateChangedCallback(in IUidFrozenStateChangedCallback callback); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)") void unregisterUidFrozenStateChangedCallback(in IUidFrozenStateChangedCallback callback); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)") + int[] getUidFrozenState(in int[] uids); } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index ef9de18d47bd..746b8f70b6af 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -47,8 +47,8 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); - void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, int displayId, @nullable ITransientNotificationCallback callback); - void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId); + void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, boolean isUiContext, int displayId, @nullable ITransientNotificationCallback callback); + void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, boolean isUiContext, int displayId); void cancelToast(String pkg, IBinder token); void finishToken(String pkg, IBinder token); diff --git a/core/java/android/app/IUserSwitchObserver.aidl b/core/java/android/app/IUserSwitchObserver.aidl index 234da8f36e96..cfdb426d6026 100644 --- a/core/java/android/app/IUserSwitchObserver.aidl +++ b/core/java/android/app/IUserSwitchObserver.aidl @@ -20,6 +20,7 @@ import android.os.IRemoteCallback; /** {@hide} */ oneway interface IUserSwitchObserver { + void onBeforeUserSwitching(int newUserId); void onUserSwitching(int newUserId, IRemoteCallback reply); void onUserSwitchComplete(int newUserId); void onForegroundProfileSwitch(int newProfileId); diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index f74be22569f0..29f774cc39d7 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -752,6 +752,29 @@ public class StatusBarManager { } /** + * Gets the last handled system key. A system key is a KeyEvent that the + * {@link com.android.server.policy.PhoneWindowManager} sends directly to the + * status bar, rather than forwarding to apps. If a key has never been sent to the + * status bar, will return -1. + * + * @return the keycode of the last KeyEvent that has been sent to the system. + * @hide + */ + @RequiresPermission(android.Manifest.permission.STATUS_BAR) + @TestApi + public int getLastSystemKey() { + try { + final IStatusBarService svc = getService(); + if (svc != null) { + return svc.getLastSystemKey(); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + return -1; + } + + /** * Expand the settings panel. * * @hide diff --git a/core/java/android/app/UserSwitchObserver.java b/core/java/android/app/UserSwitchObserver.java index 6abc4f09ba38..727799a1f948 100644 --- a/core/java/android/app/UserSwitchObserver.java +++ b/core/java/android/app/UserSwitchObserver.java @@ -30,6 +30,9 @@ public class UserSwitchObserver extends IUserSwitchObserver.Stub { } @Override + public void onBeforeUserSwitching(int newUserId) throws RemoteException {} + + @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) throws RemoteException { if (reply != null) { reply.sendResult(null); diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 540342b03f1a..4d55fee35506 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -858,6 +858,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -893,6 +895,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -1147,6 +1151,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -1176,6 +1182,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -1214,6 +1222,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -1247,6 +1257,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -1287,6 +1299,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -1314,6 +1328,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * @@ -1458,6 +1474,8 @@ public class WallpaperManager { * (some versions of T may throw a {@code SecurityException}).</li> * <li>From version U, this method should not be used * and will always throw a @code SecurityException}.</li> + * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} + * can still access the real wallpaper on all versions. </li> * </ul> * <br> * diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 924a7c659b08..bad6c77a17f3 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -15775,7 +15775,7 @@ public class DevicePolicyManager { throwIfParentInstance("setApplicationExemptions"); if (mService != null) { try { - mService.setApplicationExemptions(packageName, + mService.setApplicationExemptions(mContext.getPackageName(), packageName, ArrayUtils.convertToIntArray(new ArraySet<>(exemptions))); } catch (ServiceSpecificException e) { switch (e.errorCode) { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index e202ac2c9245..8d508c0fb79d 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -591,7 +591,7 @@ interface IDevicePolicyManager { List<UserHandle> getPolicyManagedProfiles(in UserHandle userHandle); - void setApplicationExemptions(String packageName, in int[]exemptions); + void setApplicationExemptions(String callerPackage, String packageName, in int[]exemptions); int[] getApplicationExemptions(String packageName); void setMtePolicy(int flag, String callerPackageName); diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java new file mode 100644 index 000000000000..045e4c6c77b1 --- /dev/null +++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.companion.virtual; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.PendingIntent; +import android.companion.virtual.audio.VirtualAudioDevice; +import android.companion.virtual.sensor.VirtualSensor; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.display.DisplayManagerGlobal; +import android.hardware.display.IVirtualDisplayCallback; +import android.hardware.display.VirtualDisplay; +import android.hardware.display.VirtualDisplayConfig; +import android.hardware.input.VirtualDpad; +import android.hardware.input.VirtualDpadConfig; +import android.hardware.input.VirtualKeyboard; +import android.hardware.input.VirtualKeyboardConfig; +import android.hardware.input.VirtualMouse; +import android.hardware.input.VirtualMouseConfig; +import android.hardware.input.VirtualNavigationTouchpad; +import android.hardware.input.VirtualNavigationTouchpadConfig; +import android.hardware.input.VirtualTouchscreen; +import android.hardware.input.VirtualTouchscreenConfig; +import android.media.AudioManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.util.ArrayMap; + +import com.android.internal.annotations.GuardedBy; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.function.IntConsumer; + +/** + * An internal representation of a virtual device. + * + * @hide + */ +public class VirtualDeviceInternal { + + private final Context mContext; + private final IVirtualDeviceManager mService; + private final IVirtualDevice mVirtualDevice; + private final Object mActivityListenersLock = new Object(); + @GuardedBy("mActivityListenersLock") + private final ArrayMap<VirtualDeviceManager.ActivityListener, ActivityListenerDelegate> + mActivityListeners = + new ArrayMap<>(); + private final Object mIntentInterceptorListenersLock = new Object(); + @GuardedBy("mIntentInterceptorListenersLock") + private final ArrayMap<VirtualDeviceManager.IntentInterceptorCallback, + IntentInterceptorDelegate> mIntentInterceptorListeners = + new ArrayMap<>(); + private final Object mSoundEffectListenersLock = new Object(); + @GuardedBy("mSoundEffectListenersLock") + private final ArrayMap<VirtualDeviceManager.SoundEffectListener, SoundEffectListenerDelegate> + mSoundEffectListeners = new ArrayMap<>(); + private final IVirtualDeviceActivityListener mActivityListenerBinder = + new IVirtualDeviceActivityListener.Stub() { + + @Override + public void onTopActivityChanged(int displayId, ComponentName topActivity, + @UserIdInt int userId) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mActivityListenersLock) { + for (int i = 0; i < mActivityListeners.size(); i++) { + mActivityListeners.valueAt(i) + .onTopActivityChanged(displayId, topActivity); + mActivityListeners.valueAt(i) + .onTopActivityChanged(displayId, topActivity, userId); + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onDisplayEmpty(int displayId) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mActivityListenersLock) { + for (int i = 0; i < mActivityListeners.size(); i++) { + mActivityListeners.valueAt(i).onDisplayEmpty(displayId); + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + private final IVirtualDeviceSoundEffectListener mSoundEffectListener = + new IVirtualDeviceSoundEffectListener.Stub() { + @Override + public void onPlaySoundEffect(int soundEffect) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSoundEffectListenersLock) { + for (int i = 0; i < mSoundEffectListeners.size(); i++) { + mSoundEffectListeners.valueAt(i).onPlaySoundEffect(soundEffect); + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + @Nullable + private VirtualAudioDevice mVirtualAudioDevice; + + VirtualDeviceInternal( + IVirtualDeviceManager service, + Context context, + int associationId, + VirtualDeviceParams params) throws RemoteException { + mService = service; + mContext = context.getApplicationContext(); + mVirtualDevice = service.createVirtualDevice( + new Binder(), + mContext.getPackageName(), + associationId, + params, + mActivityListenerBinder, + mSoundEffectListener); + } + + int getDeviceId() { + try { + return mVirtualDevice.getDeviceId(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @NonNull Context createContext() { + try { + return mContext.createDeviceContext(mVirtualDevice.getDeviceId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @NonNull + List<VirtualSensor> getVirtualSensorList() { + try { + return mVirtualDevice.getVirtualSensorList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + void launchPendingIntent( + int displayId, + @NonNull PendingIntent pendingIntent, + @NonNull Executor executor, + @NonNull IntConsumer listener) { + try { + mVirtualDevice.launchPendingIntent( + displayId, + pendingIntent, + new ResultReceiver(new Handler(Looper.getMainLooper())) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + super.onReceiveResult(resultCode, resultData); + executor.execute(() -> listener.accept(resultCode)); + } + }); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + @Nullable + VirtualDisplay createVirtualDisplay( + @NonNull VirtualDisplayConfig config, + @Nullable @CallbackExecutor Executor executor, + @Nullable VirtualDisplay.Callback callback) { + IVirtualDisplayCallback callbackWrapper = + new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor); + final int displayId; + try { + displayId = mService.createVirtualDisplay(config, callbackWrapper, mVirtualDevice, + mContext.getPackageName()); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance(); + return displayManager.createVirtualDisplayWrapper(config, callbackWrapper, + displayId); + } + + void close() { + try { + // This also takes care of unregistering all virtual sensors. + mVirtualDevice.close(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + if (mVirtualAudioDevice != null) { + mVirtualAudioDevice.close(); + mVirtualAudioDevice = null; + } + } + + @NonNull + VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) { + try { + final IBinder token = new Binder( + "android.hardware.input.VirtualDpad:" + config.getInputDeviceName()); + mVirtualDevice.createVirtualDpad(config, token); + return new VirtualDpad(mVirtualDevice, token); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @NonNull + VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) { + try { + final IBinder token = new Binder( + "android.hardware.input.VirtualKeyboard:" + config.getInputDeviceName()); + mVirtualDevice.createVirtualKeyboard(config, token); + return new VirtualKeyboard(mVirtualDevice, token); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @NonNull + VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) { + try { + final IBinder token = new Binder( + "android.hardware.input.VirtualMouse:" + config.getInputDeviceName()); + mVirtualDevice.createVirtualMouse(config, token); + return new VirtualMouse(mVirtualDevice, token); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @NonNull + VirtualTouchscreen createVirtualTouchscreen( + @NonNull VirtualTouchscreenConfig config) { + try { + final IBinder token = new Binder( + "android.hardware.input.VirtualTouchscreen:" + config.getInputDeviceName()); + mVirtualDevice.createVirtualTouchscreen(config, token); + return new VirtualTouchscreen(mVirtualDevice, token); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @NonNull + VirtualNavigationTouchpad createVirtualNavigationTouchpad( + @NonNull VirtualNavigationTouchpadConfig config) { + try { + final IBinder token = new Binder( + "android.hardware.input.VirtualNavigationTouchpad:" + + config.getInputDeviceName()); + mVirtualDevice.createVirtualNavigationTouchpad(config, token); + return new VirtualNavigationTouchpad(mVirtualDevice, token); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @NonNull + VirtualAudioDevice createVirtualAudioDevice( + @NonNull VirtualDisplay display, + @Nullable Executor executor, + @Nullable VirtualAudioDevice.AudioConfigurationChangeCallback callback) { + if (mVirtualAudioDevice == null) { + mVirtualAudioDevice = new VirtualAudioDevice(mContext, mVirtualDevice, display, + executor, callback, () -> mVirtualAudioDevice = null); + } + return mVirtualAudioDevice; + } + + @NonNull + void setShowPointerIcon(boolean showPointerIcon) { + try { + mVirtualDevice.setShowPointerIcon(showPointerIcon); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + void addActivityListener( + @CallbackExecutor @NonNull Executor executor, + @NonNull VirtualDeviceManager.ActivityListener listener) { + final ActivityListenerDelegate delegate = new ActivityListenerDelegate( + Objects.requireNonNull(listener), Objects.requireNonNull(executor)); + synchronized (mActivityListenersLock) { + mActivityListeners.put(listener, delegate); + } + } + + void removeActivityListener(@NonNull VirtualDeviceManager.ActivityListener listener) { + synchronized (mActivityListenersLock) { + mActivityListeners.remove(Objects.requireNonNull(listener)); + } + } + + void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor, + @NonNull VirtualDeviceManager.SoundEffectListener soundEffectListener) { + final SoundEffectListenerDelegate delegate = + new SoundEffectListenerDelegate(Objects.requireNonNull(executor), + Objects.requireNonNull(soundEffectListener)); + synchronized (mSoundEffectListenersLock) { + mSoundEffectListeners.put(soundEffectListener, delegate); + } + } + + void removeSoundEffectListener( + @NonNull VirtualDeviceManager.SoundEffectListener soundEffectListener) { + synchronized (mSoundEffectListenersLock) { + mSoundEffectListeners.remove(Objects.requireNonNull(soundEffectListener)); + } + } + + void registerIntentInterceptor( + @NonNull IntentFilter interceptorFilter, + @CallbackExecutor @NonNull Executor executor, + @NonNull VirtualDeviceManager.IntentInterceptorCallback interceptorCallback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(interceptorFilter); + Objects.requireNonNull(interceptorCallback); + final IntentInterceptorDelegate delegate = + new IntentInterceptorDelegate(executor, interceptorCallback); + try { + mVirtualDevice.registerIntentInterceptor(delegate, interceptorFilter); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + synchronized (mIntentInterceptorListenersLock) { + mIntentInterceptorListeners.put(interceptorCallback, delegate); + } + } + + void unregisterIntentInterceptor( + @NonNull VirtualDeviceManager.IntentInterceptorCallback interceptorCallback) { + Objects.requireNonNull(interceptorCallback); + final IntentInterceptorDelegate delegate; + synchronized (mIntentInterceptorListenersLock) { + delegate = mIntentInterceptorListeners.remove(interceptorCallback); + } + if (delegate != null) { + try { + mVirtualDevice.unregisterIntentInterceptor(delegate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * A wrapper for {@link VirtualDeviceManager.ActivityListener} that executes callbacks on the + * given executor. + */ + private static class ActivityListenerDelegate { + @NonNull private final VirtualDeviceManager.ActivityListener mActivityListener; + @NonNull private final Executor mExecutor; + + ActivityListenerDelegate(@NonNull VirtualDeviceManager.ActivityListener listener, + @NonNull Executor executor) { + mActivityListener = listener; + mExecutor = executor; + } + + public void onTopActivityChanged(int displayId, ComponentName topActivity) { + mExecutor.execute(() -> mActivityListener.onTopActivityChanged(displayId, topActivity)); + } + + public void onTopActivityChanged(int displayId, ComponentName topActivity, + @UserIdInt int userId) { + mExecutor.execute(() -> + mActivityListener.onTopActivityChanged(displayId, topActivity, userId)); + } + + public void onDisplayEmpty(int displayId) { + mExecutor.execute(() -> mActivityListener.onDisplayEmpty(displayId)); + } + } + + /** + * A wrapper for {@link VirtualDeviceManager.IntentInterceptorCallback} that executes callbacks + * on the given executor. + */ + private static class IntentInterceptorDelegate extends IVirtualDeviceIntentInterceptor.Stub { + @NonNull private final VirtualDeviceManager.IntentInterceptorCallback + mIntentInterceptorCallback; + @NonNull private final Executor mExecutor; + + private IntentInterceptorDelegate(Executor executor, + VirtualDeviceManager.IntentInterceptorCallback interceptorCallback) { + mExecutor = executor; + mIntentInterceptorCallback = interceptorCallback; + } + + @Override + public void onIntentIntercepted(Intent intent) { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mIntentInterceptorCallback.onIntentIntercepted(intent)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + + /** + * A wrapper for {@link VirtualDeviceManager.SoundEffectListener} that executes callbacks on the + * given executor. + */ + private static class SoundEffectListenerDelegate { + @NonNull private final VirtualDeviceManager.SoundEffectListener mSoundEffectListener; + @NonNull private final Executor mExecutor; + + private SoundEffectListenerDelegate(Executor executor, + VirtualDeviceManager.SoundEffectListener soundEffectCallback) { + mSoundEffectListener = soundEffectCallback; + mExecutor = executor; + } + + public void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType) { + mExecutor.execute(() -> mSoundEffectListener.onPlaySoundEffect(effectType)); + } + } +} diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index a7aba2108e61..d3d635e19f2e 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -32,19 +32,14 @@ import android.app.PendingIntent; import android.companion.AssociationInfo; import android.companion.virtual.audio.VirtualAudioDevice; import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback; -import android.companion.virtual.camera.VirtualCameraDevice; -import android.companion.virtual.camera.VirtualCameraInput; import android.companion.virtual.sensor.VirtualSensor; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Point; -import android.hardware.camera2.CameraCharacteristics; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.VirtualDisplayFlag; -import android.hardware.display.DisplayManagerGlobal; -import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplay; import android.hardware.display.VirtualDisplayConfig; import android.hardware.input.VirtualDpad; @@ -58,26 +53,17 @@ import android.hardware.input.VirtualNavigationTouchpadConfig; import android.hardware.input.VirtualTouchscreen; import android.hardware.input.VirtualTouchscreenConfig; import android.media.AudioManager; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; -import android.os.ResultReceiver; -import android.util.ArrayMap; import android.util.Log; import android.view.Surface; -import com.android.internal.annotations.GuardedBy; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.IntConsumer; @@ -329,7 +315,7 @@ public final class VirtualDeviceManager { } /** - * A virtual device has its own virtual display, audio output, microphone, and camera etc. The + * A virtual device has its own virtual display, audio output, microphone, sensors, etc. The * creator of a virtual device can take the output from the virtual display and stream it over * to another device, and inject input events that are received from the remote device. * @@ -340,77 +326,7 @@ public final class VirtualDeviceManager { @SystemApi public static class VirtualDevice implements AutoCloseable { - private final Context mContext; - private final IVirtualDeviceManager mService; - private final IVirtualDevice mVirtualDevice; - private final Object mActivityListenersLock = new Object(); - @GuardedBy("mActivityListenersLock") - private final ArrayMap<ActivityListener, ActivityListenerDelegate> mActivityListeners = - new ArrayMap<>(); - private final Object mIntentInterceptorListenersLock = new Object(); - @GuardedBy("mIntentInterceptorListenersLock") - private final ArrayMap<IntentInterceptorCallback, - VirtualIntentInterceptorDelegate> mIntentInterceptorListeners = - new ArrayMap<>(); - private final Object mSoundEffectListenersLock = new Object(); - @GuardedBy("mSoundEffectListenersLock") - private final ArrayMap<SoundEffectListener, SoundEffectListenerDelegate> - mSoundEffectListeners = new ArrayMap<>(); - private final IVirtualDeviceActivityListener mActivityListenerBinder = - new IVirtualDeviceActivityListener.Stub() { - - @Override - public void onTopActivityChanged(int displayId, ComponentName topActivity, - @UserIdInt int userId) { - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mActivityListenersLock) { - for (int i = 0; i < mActivityListeners.size(); i++) { - mActivityListeners.valueAt(i) - .onTopActivityChanged(displayId, topActivity); - mActivityListeners.valueAt(i) - .onTopActivityChanged(displayId, topActivity, userId); - } - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void onDisplayEmpty(int displayId) { - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mActivityListenersLock) { - for (int i = 0; i < mActivityListeners.size(); i++) { - mActivityListeners.valueAt(i).onDisplayEmpty(displayId); - } - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - }; - private final IVirtualDeviceSoundEffectListener mSoundEffectListener = - new IVirtualDeviceSoundEffectListener.Stub() { - @Override - public void onPlaySoundEffect(int soundEffect) { - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSoundEffectListenersLock) { - for (int i = 0; i < mSoundEffectListeners.size(); i++) { - mSoundEffectListeners.valueAt(i).onPlaySoundEffect(soundEffect); - } - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - }; - @Nullable - private VirtualCameraDevice mVirtualCameraDevice; - @Nullable - private VirtualAudioDevice mVirtualAudioDevice; + private final VirtualDeviceInternal mVirtualDeviceInternal; @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) private VirtualDevice( @@ -418,26 +334,15 @@ public final class VirtualDeviceManager { Context context, int associationId, VirtualDeviceParams params) throws RemoteException { - mService = service; - mContext = context.getApplicationContext(); - mVirtualDevice = service.createVirtualDevice( - new Binder(), - mContext.getPackageName(), - associationId, - params, - mActivityListenerBinder, - mSoundEffectListener); + mVirtualDeviceInternal = + new VirtualDeviceInternal(service, context, associationId, params); } /** * Returns the unique ID of this virtual device. */ public int getDeviceId() { - try { - return mVirtualDevice.getDeviceId(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mVirtualDeviceInternal.getDeviceId(); } /** @@ -445,11 +350,7 @@ public final class VirtualDeviceManager { * calling {@link Context#createDeviceContext(int)} with the device id of this device. */ public @NonNull Context createContext() { - try { - return mContext.createDeviceContext(mVirtualDevice.getDeviceId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mVirtualDeviceInternal.createContext(); } /** @@ -461,11 +362,7 @@ public final class VirtualDeviceManager { */ @NonNull public List<VirtualSensor> getVirtualSensorList() { - try { - return mVirtualDevice.getVirtualSensorList(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mVirtualDeviceInternal.getVirtualSensorList(); } /** @@ -491,20 +388,8 @@ public final class VirtualDeviceManager { @NonNull PendingIntent pendingIntent, @NonNull Executor executor, @NonNull IntConsumer listener) { - try { - mVirtualDevice.launchPendingIntent( - displayId, - pendingIntent, - new ResultReceiver(new Handler(Looper.getMainLooper())) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - super.onReceiveResult(resultCode, resultData); - executor.execute(() -> listener.accept(resultCode)); - } - }); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + mVirtualDeviceInternal.launchPendingIntent( + displayId, pendingIntent, executor, listener); } /** @@ -545,13 +430,18 @@ public final class VirtualDeviceManager { @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { + // Currently this just uses the device ID, which means all of the virtual displays + // created using the same virtual device will have the same name if they use this + // deprecated API. The name should only be used for informational purposes, and not for + // identifying the display in code. + String virtualDisplayName = "VirtualDevice_" + getDeviceId(); VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( - getVirtualDisplayName(), width, height, densityDpi) + virtualDisplayName, width, height, densityDpi) .setFlags(flags); if (surface != null) { builder.setSurface(surface); } - return createVirtualDisplay(builder.build(), executor, callback); + return mVirtualDeviceInternal.createVirtualDisplay(builder.build(), executor, callback); } /** @@ -573,18 +463,7 @@ public final class VirtualDeviceManager { @NonNull VirtualDisplayConfig config, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { - IVirtualDisplayCallback callbackWrapper = - new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor); - final int displayId; - try { - displayId = mService.createVirtualDisplay(config, callbackWrapper, mVirtualDevice, - mContext.getPackageName()); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance(); - return displayManager.createVirtualDisplayWrapper(config, callbackWrapper, - displayId); + return mVirtualDeviceInternal.createVirtualDisplay(config, executor, callback); } /** @@ -593,20 +472,7 @@ public final class VirtualDeviceManager { */ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close() { - try { - // This also takes care of unregistering all virtual sensors. - mVirtualDevice.close(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - if (mVirtualAudioDevice != null) { - mVirtualAudioDevice.close(); - mVirtualAudioDevice = null; - } - if (mVirtualCameraDevice != null) { - mVirtualCameraDevice.close(); - mVirtualCameraDevice = null; - } + mVirtualDeviceInternal.close(); } /** @@ -617,14 +483,7 @@ public final class VirtualDeviceManager { @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @NonNull public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) { - try { - final IBinder token = new Binder( - "android.hardware.input.VirtualDpad:" + config.getInputDeviceName()); - mVirtualDevice.createVirtualDpad(config, token); - return new VirtualDpad(mVirtualDevice, token); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mVirtualDeviceInternal.createVirtualDpad(config); } /** @@ -635,14 +494,7 @@ public final class VirtualDeviceManager { @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @NonNull public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) { - try { - final IBinder token = new Binder( - "android.hardware.input.VirtualKeyboard:" + config.getInputDeviceName()); - mVirtualDevice.createVirtualKeyboard(config, token); - return new VirtualKeyboard(mVirtualDevice, token); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mVirtualDeviceInternal.createVirtualKeyboard(config); } /** @@ -668,7 +520,7 @@ public final class VirtualDeviceManager { .setInputDeviceName(inputDeviceName) .setAssociatedDisplayId(display.getDisplay().getDisplayId()) .build(); - return createVirtualKeyboard(keyboardConfig); + return mVirtualDeviceInternal.createVirtualKeyboard(keyboardConfig); } /** @@ -679,14 +531,7 @@ public final class VirtualDeviceManager { @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @NonNull public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) { - try { - final IBinder token = new Binder( - "android.hardware.input.VirtualMouse:" + config.getInputDeviceName()); - mVirtualDevice.createVirtualMouse(config, token); - return new VirtualMouse(mVirtualDevice, token); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mVirtualDeviceInternal.createVirtualMouse(config); } /** @@ -713,7 +558,7 @@ public final class VirtualDeviceManager { .setInputDeviceName(inputDeviceName) .setAssociatedDisplayId(display.getDisplay().getDisplayId()) .build(); - return createVirtualMouse(mouseConfig); + return mVirtualDeviceInternal.createVirtualMouse(mouseConfig); } /** @@ -725,38 +570,7 @@ public final class VirtualDeviceManager { @NonNull public VirtualTouchscreen createVirtualTouchscreen( @NonNull VirtualTouchscreenConfig config) { - try { - final IBinder token = new Binder( - "android.hardware.input.VirtualTouchscreen:" + config.getInputDeviceName()); - mVirtualDevice.createVirtualTouchscreen(config, token); - return new VirtualTouchscreen(mVirtualDevice, token); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Creates a virtual touchpad in navigation mode. - * - * A touchpad in navigation mode means that its events are interpreted as navigation events - * (up, down, etc) instead of using them to update a cursor's absolute position. If the - * events are not consumed they are converted to DPAD events. - * - * @param config the configurations of the virtual navigation touchpad. - */ - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - @NonNull - public VirtualNavigationTouchpad createVirtualNavigationTouchpad( - @NonNull VirtualNavigationTouchpadConfig config) { - try { - final IBinder token = new Binder( - "android.hardware.input.VirtualNavigationTouchpad:" - + config.getInputDeviceName()); - mVirtualDevice.createVirtualNavigationTouchpad(config, token); - return new VirtualNavigationTouchpad(mVirtualDevice, token); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mVirtualDeviceInternal.createVirtualTouchscreen(config); } /** @@ -785,7 +599,23 @@ public final class VirtualDeviceManager { .setInputDeviceName(inputDeviceName) .setAssociatedDisplayId(display.getDisplay().getDisplayId()) .build(); - return createVirtualTouchscreen(touchscreenConfig); + return mVirtualDeviceInternal.createVirtualTouchscreen(touchscreenConfig); + } + + /** + * Creates a virtual touchpad in navigation mode. + * + * A touchpad in navigation mode means that its events are interpreted as navigation events + * (up, down, etc) instead of using them to update a cursor's absolute position. If the + * events are not consumed they are converted to DPAD events. + * + * @param config the configurations of the virtual navigation touchpad. + */ + @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) + @NonNull + public VirtualNavigationTouchpad createVirtualNavigationTouchpad( + @NonNull VirtualNavigationTouchpadConfig config) { + return mVirtualDeviceInternal.createVirtualNavigationTouchpad(config); } /** @@ -811,39 +641,7 @@ public final class VirtualDeviceManager { @NonNull VirtualDisplay display, @Nullable Executor executor, @Nullable AudioConfigurationChangeCallback callback) { - if (mVirtualAudioDevice == null) { - mVirtualAudioDevice = new VirtualAudioDevice(mContext, mVirtualDevice, display, - executor, callback, () -> mVirtualAudioDevice = null); - } - return mVirtualAudioDevice; - } - - /** - * Creates a new virtual camera. If a virtual camera was already created, it will be closed. - * - * @param cameraName name of the virtual camera. - * @param characteristics camera characteristics. - * @param virtualCameraInput callback that provides input to camera. - * @param executor Executor on which camera input will be sent into system. Don't - * use the Main Thread for this executor. - * @return newly created camera; - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - @NonNull - public VirtualCameraDevice createVirtualCameraDevice( - @NonNull String cameraName, - @NonNull CameraCharacteristics characteristics, - @NonNull VirtualCameraInput virtualCameraInput, - @NonNull Executor executor) { - if (mVirtualCameraDevice != null) { - mVirtualCameraDevice.close(); - } - int deviceId = getDeviceId(); - mVirtualCameraDevice = new VirtualCameraDevice( - deviceId, cameraName, characteristics, virtualCameraInput, executor); - return mVirtualCameraDevice; + return mVirtualDeviceInternal.createVirtualAudioDevice(display, executor, callback); } /** @@ -855,23 +653,7 @@ public final class VirtualDeviceManager { @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @NonNull public void setShowPointerIcon(boolean showPointerIcon) { - try { - mVirtualDevice.setShowPointerIcon(showPointerIcon); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private String getVirtualDisplayName() { - try { - // Currently this just use the device ID, which means all of the virtual displays - // created using the same virtual device will have the same name. The name should - // only be used for informational purposes, and not for identifying the display in - // code. - return "VirtualDevice_" + mVirtualDevice.getDeviceId(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + mVirtualDeviceInternal.setShowPointerIcon(showPointerIcon); } /** @@ -884,11 +666,7 @@ public final class VirtualDeviceManager { */ public void addActivityListener( @CallbackExecutor @NonNull Executor executor, @NonNull ActivityListener listener) { - final ActivityListenerDelegate delegate = new ActivityListenerDelegate( - Objects.requireNonNull(listener), Objects.requireNonNull(executor)); - synchronized (mActivityListenersLock) { - mActivityListeners.put(listener, delegate); - } + mVirtualDeviceInternal.addActivityListener(executor, listener); } /** @@ -899,9 +677,7 @@ public final class VirtualDeviceManager { * @see #addActivityListener(Executor, ActivityListener) */ public void removeActivityListener(@NonNull ActivityListener listener) { - synchronized (mActivityListenersLock) { - mActivityListeners.remove(Objects.requireNonNull(listener)); - } + mVirtualDeviceInternal.removeActivityListener(listener); } /** @@ -913,12 +689,7 @@ public final class VirtualDeviceManager { */ public void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor, @NonNull SoundEffectListener soundEffectListener) { - final SoundEffectListenerDelegate delegate = - new SoundEffectListenerDelegate(Objects.requireNonNull(executor), - Objects.requireNonNull(soundEffectListener)); - synchronized (mSoundEffectListenersLock) { - mSoundEffectListeners.put(soundEffectListener, delegate); - } + mVirtualDeviceInternal.addSoundEffectListener(executor, soundEffectListener); } /** @@ -928,9 +699,7 @@ public final class VirtualDeviceManager { * @see #addActivityListener(Executor, ActivityListener) */ public void removeSoundEffectListener(@NonNull SoundEffectListener soundEffectListener) { - synchronized (mSoundEffectListenersLock) { - mSoundEffectListeners.remove(Objects.requireNonNull(soundEffectListener)); - } + mVirtualDeviceInternal.removeSoundEffectListener(soundEffectListener); } /** @@ -949,19 +718,8 @@ public final class VirtualDeviceManager { @NonNull IntentFilter interceptorFilter, @CallbackExecutor @NonNull Executor executor, @NonNull IntentInterceptorCallback interceptorCallback) { - Objects.requireNonNull(executor); - Objects.requireNonNull(interceptorFilter); - Objects.requireNonNull(interceptorCallback); - final VirtualIntentInterceptorDelegate delegate = - new VirtualIntentInterceptorDelegate(executor, interceptorCallback); - try { - mVirtualDevice.registerIntentInterceptor(delegate, interceptorFilter); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - synchronized (mIntentInterceptorListenersLock) { - mIntentInterceptorListeners.put(interceptorCallback, delegate); - } + mVirtualDeviceInternal.registerIntentInterceptor( + interceptorFilter, executor, interceptorCallback); } /** @@ -971,18 +729,7 @@ public final class VirtualDeviceManager { @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void unregisterIntentInterceptor( @NonNull IntentInterceptorCallback interceptorCallback) { - Objects.requireNonNull(interceptorCallback); - final VirtualIntentInterceptorDelegate delegate; - synchronized (mIntentInterceptorListenersLock) { - delegate = mIntentInterceptorListeners.remove(interceptorCallback); - } - if (delegate != null) { - try { - mVirtualDevice.unregisterIntentInterceptor(delegate); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + mVirtualDeviceInternal.unregisterIntentInterceptor(interceptorCallback); } } @@ -1031,33 +778,6 @@ public final class VirtualDeviceManager { } /** - * A wrapper for {@link ActivityListener} that executes callbacks on the given executor. - */ - private static class ActivityListenerDelegate { - @NonNull private final ActivityListener mActivityListener; - @NonNull private final Executor mExecutor; - - ActivityListenerDelegate(@NonNull ActivityListener listener, @NonNull Executor executor) { - mActivityListener = listener; - mExecutor = executor; - } - - public void onTopActivityChanged(int displayId, ComponentName topActivity) { - mExecutor.execute(() -> mActivityListener.onTopActivityChanged(displayId, topActivity)); - } - - public void onTopActivityChanged(int displayId, ComponentName topActivity, - @UserIdInt int userId) { - mExecutor.execute(() -> - mActivityListener.onTopActivityChanged(displayId, topActivity, userId)); - } - - public void onDisplayEmpty(int displayId) { - mExecutor.execute(() -> mActivityListener.onDisplayEmpty(displayId)); - } - } - - /** * Interceptor interface to be called when an intent matches the IntentFilter passed into {@link * VirtualDevice#registerIntentInterceptor}. When the interceptor is called after matching the * IntentFilter, the intended activity launch will be aborted and alternatively replaced by @@ -1079,32 +799,6 @@ public final class VirtualDeviceManager { } /** - * A wrapper for {@link IntentInterceptorCallback} that executes callbacks on the - * the given executor. - */ - private static class VirtualIntentInterceptorDelegate - extends IVirtualDeviceIntentInterceptor.Stub { - @NonNull private final IntentInterceptorCallback mIntentInterceptorCallback; - @NonNull private final Executor mExecutor; - - private VirtualIntentInterceptorDelegate(Executor executor, - IntentInterceptorCallback interceptorCallback) { - mExecutor = executor; - mIntentInterceptorCallback = interceptorCallback; - } - - @Override - public void onIntentIntercepted(Intent intent) { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mIntentInterceptorCallback.onIntentIntercepted(intent)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - } - - /** * Listener for system sound effect playback on virtual device. * @hide */ @@ -1119,22 +813,4 @@ public final class VirtualDeviceManager { */ void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType); } - - /** - * A wrapper for {@link SoundEffectListener} that executes callbacks on the given executor. - */ - private static class SoundEffectListenerDelegate { - @NonNull private final SoundEffectListener mSoundEffectListener; - @NonNull private final Executor mExecutor; - - private SoundEffectListenerDelegate(Executor executor, - SoundEffectListener soundEffectCallback) { - mSoundEffectListener = soundEffectCallback; - mExecutor = executor; - } - - public void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType) { - mExecutor.execute(() -> mSoundEffectListener.onPlaySoundEffect(effectType)); - } - } } diff --git a/core/java/android/companion/virtual/camera/VirtualCameraDevice.java b/core/java/android/companion/virtual/camera/VirtualCameraDevice.java deleted file mode 100644 index a7eba873445c..000000000000 --- a/core/java/android/companion/virtual/camera/VirtualCameraDevice.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.companion.virtual.camera; - -import android.hardware.camera2.CameraCharacteristics; - -import androidx.annotation.NonNull; - -import java.util.Locale; -import java.util.Objects; -import java.util.concurrent.Executor; - -/** - * Virtual camera that is used to send image data into system. - * - * @hide - */ -public final class VirtualCameraDevice implements AutoCloseable { - - @NonNull - private final String mCameraDeviceName; - @NonNull - private final CameraCharacteristics mCameraCharacteristics; - @NonNull - private final VirtualCameraOutput mCameraOutput; - private boolean mCameraRegistered = false; - - /** - * VirtualCamera device constructor. - * - * @param virtualDeviceId ID of virtual device to which camera will be added. - * @param cameraName must be unique for each camera per virtual device. - * @param characteristics of camera that will be passed into system in order to describe - * camera. - * @param virtualCameraInput component that provides image data. - * @param executor on which to collect image data and pass it into system. - */ - public VirtualCameraDevice(int virtualDeviceId, @NonNull String cameraName, - @NonNull CameraCharacteristics characteristics, - @NonNull VirtualCameraInput virtualCameraInput, @NonNull Executor executor) { - Objects.requireNonNull(cameraName); - mCameraCharacteristics = Objects.requireNonNull(characteristics); - mCameraDeviceName = generateCameraDeviceName(virtualDeviceId, cameraName); - mCameraOutput = new VirtualCameraOutput(virtualCameraInput, executor); - registerCamera(); - } - - private static String generateCameraDeviceName(int deviceId, @NonNull String cameraName) { - return String.format(Locale.ENGLISH, "%d_%s", deviceId, Objects.requireNonNull(cameraName)); - } - - @Override - public void close() { - if (!mCameraRegistered) { - return; - } - - mCameraOutput.closeStream(); - } - - private void registerCamera() { - if (mCameraRegistered) { - return; - } - - mCameraRegistered = true; - } -} diff --git a/core/java/android/companion/virtual/camera/VirtualCameraInput.java b/core/java/android/companion/virtual/camera/VirtualCameraInput.java deleted file mode 100644 index 690a64b7fd23..000000000000 --- a/core/java/android/companion/virtual/camera/VirtualCameraInput.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.companion.virtual.camera; - -import android.annotation.NonNull; -import android.hardware.camera2.params.InputConfiguration; - -import java.io.InputStream; - -/*** - * Used for sending image data into virtual camera. - * <p> - * The system will call {@link #openStream(InputConfiguration)} to signal when you - * should start sending Camera image data. - * When Camera is no longer needed, or there is change in configuration - * {@link #closeStream()} will be called. At that time finish sending current - * image data and then close the stream. - * <p> - * If Camera image data is needed again, {@link #openStream(InputConfiguration)} will be - * called by the system. - * - * @hide - */ -public interface VirtualCameraInput { - - /** - * Opens a new image stream for the provided {@link InputConfiguration}. - * - * @param inputConfiguration image data configuration. - * @return image data stream. - */ - @NonNull - InputStream openStream(@NonNull InputConfiguration inputConfiguration); - - /** - * Stop sending image data and close {@link InputStream} provided in {@link - * #openStream(InputConfiguration)}. Do nothing if there is currently no active stream. - */ - void closeStream(); -} diff --git a/core/java/android/companion/virtual/camera/VirtualCameraOutput.java b/core/java/android/companion/virtual/camera/VirtualCameraOutput.java deleted file mode 100644 index fa1c3ad23ab8..000000000000 --- a/core/java/android/companion/virtual/camera/VirtualCameraOutput.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.companion.virtual.camera; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.hardware.camera2.params.InputConfiguration; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; -import java.util.concurrent.Executor; - -/** - * Component for providing Camera data to the system. - * <p> - * {@link #getStreamDescriptor(InputConfiguration)} will be called by the system when Camera should - * start sending image data. Camera data will continue to be sent into {@link ParcelFileDescriptor} - * until {@link #closeStream()} is called by the system, at which point {@link ParcelFileDescriptor} - * will be closed. - * - * @hide - */ -@VisibleForTesting -public class VirtualCameraOutput { - - private static final String TAG = "VirtualCameraDeviceImpl"; - - @NonNull - private final VirtualCameraInput mVirtualCameraInput; - @NonNull - private final Executor mExecutor; - @Nullable - private VirtualCameraStream mCameraStream; - - @VisibleForTesting - public VirtualCameraOutput(@NonNull VirtualCameraInput cameraInput, - @NonNull Executor executor) { - mVirtualCameraInput = Objects.requireNonNull(cameraInput); - mExecutor = Objects.requireNonNull(executor); - } - - /** - * Get a read Descriptor on which Camera HAL will receive data. At any point in time there can - * exist a maximum of one active {@link ParcelFileDescriptor}. - * Calling this method with a different {@link InputConfiguration} is going to close the - * previously created file descriptor. - * - * @param imageConfiguration for which to create the {@link ParcelFileDescriptor}. - * @return Newly created ParcelFileDescriptor if stream param is different from previous or if - * this is first time call. Will return null if there was an error during Descriptor - * creation process. - */ - @Nullable - @VisibleForTesting - public ParcelFileDescriptor getStreamDescriptor( - @NonNull InputConfiguration imageConfiguration) { - Objects.requireNonNull(imageConfiguration); - - // Reuse same descriptor if stream is the same, otherwise create a new one. - try { - if (mCameraStream == null) { - mCameraStream = new VirtualCameraStream(imageConfiguration, mExecutor); - } else if (!mCameraStream.isSameConfiguration(imageConfiguration)) { - mCameraStream.close(); - mCameraStream = new VirtualCameraStream(imageConfiguration, mExecutor); - } - } catch (IOException exception) { - Log.e(TAG, "Unable to open file descriptor.", exception); - return null; - } - - InputStream imageStream = mVirtualCameraInput.openStream(imageConfiguration); - mCameraStream.startSending(imageStream); - return mCameraStream.getDescriptor(); - } - - /** - * Closes currently opened stream. If there is no stream, do nothing. - */ - @VisibleForTesting - public void closeStream() { - mVirtualCameraInput.closeStream(); - if (mCameraStream != null) { - mCameraStream.close(); - mCameraStream = null; - } - - try { - mVirtualCameraInput.closeStream(); - } catch (Exception e) { - Log.e(TAG, "Error during closing stream.", e); - } - } - - private static class VirtualCameraStream implements AutoCloseable { - - private static final String TAG = "VirtualCameraStream"; - private static final int BUFFER_SIZE = 1024; - - private static final int SENDING_STATE_INITIAL = 0; - private static final int SENDING_STATE_IN_PROGRESS = 1; - private static final int SENDING_STATE_CLOSED = 2; - - @NonNull - private final InputConfiguration mImageConfiguration; - @NonNull - private final Executor mExecutor; - @Nullable - private final ParcelFileDescriptor mReadDescriptor; - @Nullable - private final ParcelFileDescriptor mWriteDescriptor; - private int mSendingState; - - VirtualCameraStream(@NonNull InputConfiguration imageConfiguration, - @NonNull Executor executor) throws IOException { - mSendingState = SENDING_STATE_INITIAL; - mImageConfiguration = Objects.requireNonNull(imageConfiguration); - mExecutor = Objects.requireNonNull(executor); - ParcelFileDescriptor[] parcels = ParcelFileDescriptor.createPipe(); - mReadDescriptor = parcels[0]; - mWriteDescriptor = parcels[1]; - } - - boolean isSameConfiguration(@NonNull InputConfiguration imageConfiguration) { - return mImageConfiguration == Objects.requireNonNull(imageConfiguration); - } - - @Nullable - ParcelFileDescriptor getDescriptor() { - return mReadDescriptor; - } - - public void startSending(@NonNull InputStream inputStream) { - Objects.requireNonNull(inputStream); - - if (mSendingState != SENDING_STATE_INITIAL) { - return; - } - - mSendingState = SENDING_STATE_IN_PROGRESS; - mExecutor.execute(() -> sendData(inputStream)); - } - - @Override - public void close() { - mSendingState = SENDING_STATE_CLOSED; - try { - mReadDescriptor.close(); - } catch (IOException e) { - Log.e(TAG, "Unable to close read descriptor.", e); - } - try { - mWriteDescriptor.close(); - } catch (IOException e) { - Log.e(TAG, "Unable to close write descriptor.", e); - } - } - - private void sendData(@NonNull InputStream inputStream) { - Objects.requireNonNull(inputStream); - - byte[] buffer = new byte[BUFFER_SIZE]; - FileDescriptor fd = mWriteDescriptor.getFileDescriptor(); - try (FileOutputStream outputStream = new FileOutputStream(fd)) { - while (mSendingState == SENDING_STATE_IN_PROGRESS) { - int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE); - if (bytesRead < 1) continue; - - outputStream.write(buffer, 0, bytesRead); - } - } catch (IOException e) { - Log.e(TAG, "Error while sending camera data.", e); - } - } - } -} diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index 8a22ce3a75f8..107f1078b11e 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -85,7 +85,7 @@ public class ClipboardManager extends android.text.ClipboardManager { * * @hide */ - public static final boolean DEVICE_CONFIG_DEFAULT_ALLOW_VIRTUALDEVICE_SILOS = false; + public static final boolean DEVICE_CONFIG_DEFAULT_ALLOW_VIRTUALDEVICE_SILOS = true; private final Context mContext; private final Handler mHandler; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 3b2ea785988e..2b73afcd740f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -322,6 +322,7 @@ public abstract class Context { BIND_EXTERNAL_SERVICE_LONG, // Make sure no flag uses the sign bit (most significant bit) of the long integer, // to avoid future confusion. + BIND_BYPASS_USER_NETWORK_RESTRICTIONS, }) @Retention(RetentionPolicy.SOURCE) public @interface BindServiceFlagsLongBits {} @@ -688,6 +689,16 @@ public abstract class Context { public static final long BIND_EXTERNAL_SERVICE_LONG = 1L << 62; /** + * Flag for {@link #bindService}: allow the process hosting the target service to gain + * {@link ActivityManager#PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK}, which allows it be able + * to access network regardless of any user restrictions. + * + * @hide + */ + public static final long BIND_BYPASS_USER_NETWORK_RESTRICTIONS = 0x1_0000_0000L; + + + /** * These bind flags reduce the strength of the binding such that we shouldn't * consider it as pulling the process up to the level of the one that is bound to it. * @hide diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index df8da246c976..58b0571653f1 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -11356,12 +11356,15 @@ public class Intent implements Parcelable, Cloneable { @Override public String toString() { StringBuilder b = new StringBuilder(128); + toString(b); + return b.toString(); + } + /** @hide */ + public void toString(@NonNull StringBuilder b) { b.append("Intent { "); toShortString(b, true, true, true, false); b.append(" }"); - - return b.toString(); } /** @hide */ diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 8aa9b739acf9..b5d2f2c9177a 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1083,6 +1083,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Overridable @Disabled + @TestApi public static final long OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION = 254631730L; // buganizer id @@ -1142,6 +1143,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Overridable @Disabled + @TestApi public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION = 263959004L; // buganizer id @@ -1154,6 +1156,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Overridable @Disabled + @TestApi public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH = 264304459L; // buganizer id /** @@ -1166,6 +1169,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Overridable @Disabled + @TestApi public static final long OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE = 264301586L; // buganizer id @@ -1292,6 +1296,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Disabled @Overridable + @TestApi public static final long OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS = 263259275L; // Compat framework that per-app overrides rely on only supports booleans. That's why we have @@ -1307,6 +1312,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Disabled @Overridable + @TestApi public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT = 265452344L; /** @@ -1318,6 +1324,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Disabled @Overridable + @TestApi public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR = 265451093L; /** @@ -1331,6 +1338,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Disabled @Overridable + @TestApi public static final long OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE = 266124927L; /** @@ -1377,6 +1385,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ChangeId @Disabled @Overridable + @TestApi public static final long OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION = 255940284L; /** diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 21e2a131bcac..eb3d37d6e14f 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3046,6 +3046,17 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device contains support for installing SDKs to a work + * profile. + * + * @hide + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_SDK_SANDBOX_WORK_PROFILE_INSTALL = + "android.software.sdksandbox.sdk_install_work_profile"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports Open Mobile API capable UICC-based secure * elements. */ diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 1a3c3d97634c..7e0954a55560 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -332,7 +332,6 @@ public class ServiceInfo extends ComponentInfo * permissions: * {@link android.Manifest.permission#ACTIVITY_RECOGNITION}, * {@link android.Manifest.permission#BODY_SENSORS}, - * {@link android.Manifest.permission#BODY_SENSORS_WRIST_TEMPERATURE}, * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}. */ @RequiresPermission( @@ -342,7 +341,6 @@ public class ServiceInfo extends ComponentInfo anyOf = { Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission.BODY_SENSORS, - Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE, Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, } ) diff --git a/core/java/android/credentials/CredentialDescription.java b/core/java/android/credentials/CredentialDescription.java index a23d7e402768..db71624cbe89 100644 --- a/core/java/android/credentials/CredentialDescription.java +++ b/core/java/android/credentials/CredentialDescription.java @@ -25,8 +25,10 @@ import com.android.internal.util.AnnotationValidations; import com.android.internal.util.Preconditions; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Represents the type and contained data fields of a {@link Credential}. @@ -42,10 +44,10 @@ public final class CredentialDescription implements Parcelable { private final String mType; /** - * Flattened semicolon separated keys of JSON values to match with requests. + * Keys of elements to match with Credential requests. */ @NonNull - private final String mFlattenedRequestString; + private final Set<String> mSupportedElementKeys; /** * The credential entries to be used in the UI. @@ -57,8 +59,7 @@ public final class CredentialDescription implements Parcelable { * Constructs a {@link CredentialDescription}. * * @param type the type of the credential returned. - * @param flattenedRequestString flattened semicolon separated keys of JSON values - * to match with requests. + * @param supportedElementKeys Keys of elements to match with Credential requests. * @param credentialEntries a list of {@link CredentialEntry}s that are to be shown on the * account selector if a credential matches with this description. * Each entry contains information to be displayed within an @@ -68,10 +69,10 @@ public final class CredentialDescription implements Parcelable { * @throws IllegalArgumentException If type is empty. */ public CredentialDescription(@NonNull String type, - @NonNull String flattenedRequestString, + @NonNull Set<String> supportedElementKeys, @NonNull List<CredentialEntry> credentialEntries) { mType = Preconditions.checkStringNotEmpty(type, "type must not be empty"); - mFlattenedRequestString = Preconditions.checkStringNotEmpty(flattenedRequestString); + mSupportedElementKeys = Objects.requireNonNull(supportedElementKeys); mCredentialEntries = Objects.requireNonNull(credentialEntries); Preconditions.checkArgument(credentialEntries.size() <= MAX_ALLOWED_ENTRIES_PER_DESCRIPTION, @@ -82,15 +83,15 @@ public final class CredentialDescription implements Parcelable { private CredentialDescription(@NonNull Parcel in) { String type = in.readString8(); - String flattenedRequestString = in.readString(); + List<String> descriptions = in.createStringArrayList(); List<CredentialEntry> entries = new ArrayList<>(); in.readTypedList(entries, CredentialEntry.CREATOR); mType = type; AnnotationValidations.validate(android.annotation.NonNull.class, null, mType); - mFlattenedRequestString = flattenedRequestString; + mSupportedElementKeys = new HashSet<>(descriptions); AnnotationValidations.validate(android.annotation.NonNull.class, null, - mFlattenedRequestString); + mSupportedElementKeys); mCredentialEntries = entries; AnnotationValidations.validate(android.annotation.NonNull.class, null, mCredentialEntries); @@ -125,7 +126,7 @@ public final class CredentialDescription implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); - dest.writeString(mFlattenedRequestString); + dest.writeStringList(mSupportedElementKeys.stream().toList()); dest.writeTypedList(mCredentialEntries, flags); } @@ -141,8 +142,8 @@ public final class CredentialDescription implements Parcelable { * Returns the flattened JSON string that will be matched with requests. */ @NonNull - public String getFlattenedRequestString() { - return mFlattenedRequestString; + public Set<String> getSupportedElementKeys() { + return new HashSet<>(mSupportedElementKeys); } /** @@ -155,18 +156,18 @@ public final class CredentialDescription implements Parcelable { /** * {@link CredentialDescription#mType} and - * {@link CredentialDescription#mFlattenedRequestString} are enough for hashing. Constructor + * {@link CredentialDescription#mSupportedElementKeys} are enough for hashing. Constructor * enforces {@link CredentialEntry} to have the same type and * {@link android.app.slice.Slice} contained by the entry can not be hashed. */ @Override public int hashCode() { - return Objects.hash(mType, mFlattenedRequestString); + return Objects.hash(mType, mSupportedElementKeys); } /** * {@link CredentialDescription#mType} and - * {@link CredentialDescription#mFlattenedRequestString} are enough for equality check. + * {@link CredentialDescription#mSupportedElementKeys} are enough for equality check. */ @Override public boolean equals(Object obj) { @@ -175,6 +176,6 @@ public final class CredentialDescription implements Parcelable { } CredentialDescription other = (CredentialDescription) obj; return mType.equals(other.mType) - && mFlattenedRequestString.equals(other.mFlattenedRequestString); + && mSupportedElementKeys.equals(other.mSupportedElementKeys); } } diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index 5579d2263d06..00ce17adfda6 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -25,11 +25,11 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.TestApi; -import android.app.Activity; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; +import android.os.Binder; import android.os.CancellationSignal; import android.os.ICancellationSignal; import android.os.OutcomeReceiver; @@ -126,20 +126,21 @@ public final class CredentialManager { * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN} * to use this functionality * + * @param context the context used to launch any UI needed; use an activity context to make sure + * the UI will be launched within the same task stack * @param request the request specifying type(s) of credentials to get from the user - * @param activity the activity used to launch any UI needed * @param cancellationSignal an optional signal that allows for cancelling this call * @param executor the callback will take place on this {@link Executor} * @param callback the callback invoked when the request succeeds or fails */ public void getCredential( + @NonNull Context context, @NonNull GetCredentialRequest request, - @NonNull Activity activity, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { requireNonNull(request, "request must not be null"); - requireNonNull(activity, "activity must not be null"); + requireNonNull(context, "context must not be null"); requireNonNull(executor, "executor must not be null"); requireNonNull(callback, "callback must not be null"); @@ -153,7 +154,7 @@ public final class CredentialManager { cancelRemote = mService.executeGetCredential( request, - new GetCredentialTransport(activity, executor, callback), + new GetCredentialTransport(context, executor, callback), mContext.getOpPackageName()); } catch (RemoteException e) { e.rethrowFromSystemServer(); @@ -175,21 +176,22 @@ public final class CredentialManager { * request through the {@link #prepareGetCredential( * GetCredentialRequest, CancellationSignal, Executor, OutcomeReceiver)} API. * + * @param context the context used to launch any UI needed; use an activity context to make sure + * the UI will be launched within the same task stack * @param pendingGetCredentialHandle the handle representing the pending operation to resume - * @param activity the activity used to launch any UI needed * @param cancellationSignal an optional signal that allows for cancelling this call * @param executor the callback will take place on this {@link Executor} * @param callback the callback invoked when the request succeeds or fails */ public void getCredential( + @NonNull Context context, @NonNull PrepareGetCredentialResponse.PendingGetCredentialHandle - pendingGetCredentialHandle, - @NonNull Activity activity, + pendingGetCredentialHandle, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { requireNonNull(pendingGetCredentialHandle, "pendingGetCredentialHandle must not be null"); - requireNonNull(activity, "activity must not be null"); + requireNonNull(context, "context must not be null"); requireNonNull(executor, "executor must not be null"); requireNonNull(callback, "callback must not be null"); @@ -198,7 +200,7 @@ public final class CredentialManager { return; } - pendingGetCredentialHandle.show(activity, cancellationSignal, executor, callback); + pendingGetCredentialHandle.show(context, cancellationSignal, executor, callback); } /** @@ -207,9 +209,9 @@ public final class CredentialManager { * * <p>This API doesn't invoke any UI. It only performs the preparation work so that you can * later launch the remaining get-credential operation (involves UIs) through the {@link - * #getCredential(PrepareGetCredentialResponse.PendingGetCredentialHandle, Activity, + * #getCredential(PrepareGetCredentialResponse.PendingGetCredentialHandle, Context, * CancellationSignal, Executor, OutcomeReceiver)} API which incurs less latency compared to - * the {@link #getCredential(GetCredentialRequest, Activity, CancellationSignal, Executor, + * the {@link #getCredential(GetCredentialRequest, Context, CancellationSignal, Executor, * OutcomeReceiver)} API that executes the whole operation in one call. * * @param request the request specifying type(s) of credentials to get from the user @@ -262,21 +264,22 @@ public final class CredentialManager { * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN} * to use this functionality * + * @param context the context used to launch any UI needed; use an activity context to make sure + * the UI will be launched within the same task stack * @param request the request specifying type(s) of credentials to get from the user - * @param activity the activity used to launch any UI needed * @param cancellationSignal an optional signal that allows for cancelling this call * @param executor the callback will take place on this {@link Executor} * @param callback the callback invoked when the request succeeds or fails */ public void createCredential( + @NonNull Context context, @NonNull CreateCredentialRequest request, - @NonNull Activity activity, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback) { requireNonNull(request, "request must not be null"); - requireNonNull(activity, "activity must not be null"); + requireNonNull(context, "context must not be null"); requireNonNull(executor, "executor must not be null"); requireNonNull(callback, "callback must not be null"); @@ -290,7 +293,7 @@ public final class CredentialManager { cancelRemote = mService.executeCreateCredential( request, - new CreateCredentialTransport(activity, executor, callback), + new CreateCredentialTransport(context, executor, callback), mContext.getOpPackageName()); } catch (RemoteException e) { e.rethrowFromSystemServer(); @@ -547,14 +550,24 @@ public final class CredentialManager { @Override public void onResponse(PrepareGetCredentialResponseInternal response) { - mExecutor.execute(() -> mCallback.onResult( - new PrepareGetCredentialResponse(response, mGetCredentialTransport))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult( + new PrepareGetCredentialResponse(response, mGetCredentialTransport))); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new GetCredentialException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError(new GetCredentialException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -587,7 +600,12 @@ public final class CredentialManager { @Override public void onResponse(GetCredentialResponse response) { if (mCallback != null) { - mCallback.onResponse(response); + final long identity = Binder.clearCallingIdentity(); + try { + mCallback.onResponse(response); + } finally { + Binder.restoreCallingIdentity(identity); + } } else { Log.d(TAG, "Unexpected onResponse call before the show invocation"); } @@ -596,7 +614,12 @@ public final class CredentialManager { @Override public void onError(String errorType, String message) { if (mCallback != null) { - mCallback.onError(errorType, message); + final long identity = Binder.clearCallingIdentity(); + try { + mCallback.onError(errorType, message); + } finally { + Binder.restoreCallingIdentity(identity); + } } else { Log.d(TAG, "Unexpected onError call before the show invocation"); } @@ -606,15 +629,15 @@ public final class CredentialManager { private static class GetCredentialTransport extends IGetCredentialCallback.Stub { // TODO: listen for cancellation to release callback. - private final Activity mActivity; + private final Context mContext; private final Executor mExecutor; private final OutcomeReceiver<GetCredentialResponse, GetCredentialException> mCallback; private GetCredentialTransport( - Activity activity, + Context context, Executor executor, OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { - mActivity = activity; + mContext = context; mExecutor = executor; mCallback = callback; } @@ -622,42 +645,57 @@ public final class CredentialManager { @Override public void onPendingIntent(PendingIntent pendingIntent) { try { - mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); + mContext.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e( TAG, "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(), e); - mExecutor.execute(() -> mCallback.onError( - new GetCredentialException(GetCredentialException.TYPE_UNKNOWN))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onError( + new GetCredentialException(GetCredentialException.TYPE_UNKNOWN))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override public void onResponse(GetCredentialResponse response) { - mExecutor.execute(() -> mCallback.onResult(response)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(response)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new GetCredentialException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError(new GetCredentialException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } private static class CreateCredentialTransport extends ICreateCredentialCallback.Stub { // TODO: listen for cancellation to release callback. - private final Activity mActivity; + private final Context mContext; private final Executor mExecutor; private final OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> mCallback; private CreateCredentialTransport( - Activity activity, + Context context, Executor executor, OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback) { - mActivity = activity; + mContext = context; mExecutor = executor; mCallback = callback; } @@ -665,26 +703,41 @@ public final class CredentialManager { @Override public void onPendingIntent(PendingIntent pendingIntent) { try { - mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); + mContext.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e( TAG, "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(), e); - mExecutor.execute(() -> mCallback.onError( - new CreateCredentialException(CreateCredentialException.TYPE_UNKNOWN))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onError( + new CreateCredentialException(CreateCredentialException.TYPE_UNKNOWN))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override public void onResponse(CreateCredentialResponse response) { - mExecutor.execute(() -> mCallback.onResult(response)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(response)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new CreateCredentialException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError(new CreateCredentialException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -702,13 +755,24 @@ public final class CredentialManager { @Override public void onSuccess() { - mCallback.onResult(null); + final long identity = Binder.clearCallingIdentity(); + try { + mCallback.onResult(null); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new ClearCredentialStateException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError( + new ClearCredentialStateException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -725,18 +789,34 @@ public final class CredentialManager { } public void onResponse(Void result) { - mExecutor.execute(() -> mCallback.onResult(result)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(result)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onResponse() { - mExecutor.execute(() -> mCallback.onResult(null)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(null)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new SetEnabledProvidersException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError( + new SetEnabledProvidersException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } } diff --git a/core/java/android/credentials/CredentialOption.java b/core/java/android/credentials/CredentialOption.java index da6656a0222f..e933123d08b8 100644 --- a/core/java/android/credentials/CredentialOption.java +++ b/core/java/android/credentials/CredentialOption.java @@ -43,12 +43,12 @@ import java.util.Set; public final class CredentialOption implements Parcelable { /** - * Bundle key to the flattened version of the JSON request string. Framework will use this key + * Bundle key to the list of elements keys supported/requested. Framework will use this key * to determine which types of Credentials will utilize Credential Registry when filtering * Credential Providers to ping. */ - public static final String FLATTENED_REQUEST = "android.credentials" - + ".GetCredentialOption.FLATTENED_REQUEST_STRING"; + public static final String SUPPORTED_ELEMENT_KEYS = "android.credentials" + + ".GetCredentialOption.SUPPORTED_ELEMENT_KEYS"; /** * The requested credential type. diff --git a/core/java/android/credentials/PrepareGetCredentialResponse.java b/core/java/android/credentials/PrepareGetCredentialResponse.java index 81e906859cb8..056b18a51b6d 100644 --- a/core/java/android/credentials/PrepareGetCredentialResponse.java +++ b/core/java/android/credentials/PrepareGetCredentialResponse.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.app.Activity; import android.app.PendingIntent; +import android.content.Context; import android.content.IntentSender; import android.os.CancellationSignal; import android.os.OutcomeReceiver; @@ -67,7 +68,7 @@ public final class PrepareGetCredentialResponse { } /** @hide */ - void show(@NonNull Activity activity, @Nullable CancellationSignal cancellationSignal, + void show(@NonNull Context context, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { if (mPendingIntent == null) { @@ -80,7 +81,7 @@ public final class PrepareGetCredentialResponse { @Override public void onPendingIntent(PendingIntent pendingIntent) { try { - activity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); + context.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e(TAG, "startIntentSender() failed for intent for show()", e); executor.execute(() -> callback.onError( @@ -101,7 +102,7 @@ public final class PrepareGetCredentialResponse { }); try { - activity.startIntentSender(mPendingIntent.getIntentSender(), null, 0, 0, 0); + context.startIntentSender(mPendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e(TAG, "startIntentSender() failed for intent for show()", e); executor.execute(() -> callback.onError( diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 81d6ba93cfe9..ccc39b6080d7 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -51,6 +51,7 @@ import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; @@ -486,8 +487,22 @@ public class Camera { boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait( ActivityThread.currentApplication().getApplicationContext()); + boolean forceSlowJpegMode = shouldForceSlowJpegMode(); return native_setup(new WeakReference<Camera>(this), cameraId, - ActivityThread.currentOpPackageName(), overrideToPortrait); + ActivityThread.currentOpPackageName(), overrideToPortrait, forceSlowJpegMode); + } + + private boolean shouldForceSlowJpegMode() { + Context applicationContext = ActivityThread.currentApplication().getApplicationContext(); + String[] slowJpegPackageNames = applicationContext.getResources().getStringArray( + R.array.config_forceSlowJpegModeList); + String callingPackageName = applicationContext.getPackageName(); + for (String packageName : slowJpegPackageNames) { + if (TextUtils.equals(packageName, callingPackageName)) { + return true; + } + } + return false; } /** used by Camera#open, Camera#open(int) */ @@ -558,7 +573,7 @@ public class Camera { @UnsupportedAppUsage private native int native_setup(Object cameraThis, int cameraId, String packageName, - boolean overrideToPortrait); + boolean overrideToPortrait, boolean forceSlowJpegMode); private native final void native_release(); diff --git a/core/java/android/hardware/DataSpace.java b/core/java/android/hardware/DataSpace.java index b8b1eaaa164c..312bfdf777d6 100644 --- a/core/java/android/hardware/DataSpace.java +++ b/core/java/android/hardware/DataSpace.java @@ -16,6 +16,7 @@ package android.hardware; import android.annotation.IntDef; +import android.view.SurfaceControl; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -376,12 +377,19 @@ public final class DataSpace { */ public static final int RANGE_LIMITED = 2 << 27; /** - * Extended range is used for scRGB only. + * Extended range can be used in combination with FP16 to communicate scRGB or with + * {@link android.view.SurfaceControl.Transaction#setExtendedRangeBrightness(SurfaceControl, float, float)} + * to indicate an HDR range. * - * <p>Intended for use with floating point pixel formats. [0.0 - 1.0] is the standard - * sRGB space. Values outside the range [0.0 - 1.0] can encode - * color outside the sRGB gamut. [-0.5, 7.5] is the scRGB range. + * <p>When used with floating point pixel formats and #STANDARD_BT709 then [0.0 - 1.0] is the + * standard sRGB space and values outside the range [0.0 - 1.0] can encode + * color outside the sRGB gamut. [-0.5, 7.5] is the standard scRGB range. * Used to blend/merge multiple dataspaces on a single display.</p> + * + * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} this may be combined with + * {@link android.view.SurfaceControl.Transaction#setExtendedRangeBrightness(SurfaceControl, float, float)} + * and other formats such as {@link HardwareBuffer#RGBA_8888} or + * {@link HardwareBuffer#RGBA_1010102} to communicate a variable HDR brightness range</p> */ public static final int RANGE_EXTENDED = 3 << 27; diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 0e4c3c0f12a1..e908ced06acd 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -41,9 +41,12 @@ import java.util.Set; * <p>The properties describing a * {@link CameraDevice CameraDevice}.</p> * - * <p>These properties are fixed for a given CameraDevice, and can be queried + * <p>These properties are primarily fixed for a given CameraDevice, and can be queried * through the {@link CameraManager CameraManager} - * interface with {@link CameraManager#getCameraCharacteristics}.</p> + * interface with {@link CameraManager#getCameraCharacteristics}. Beginning with API level 32, some + * properties such as {@link #SENSOR_ORIENTATION} may change dynamically based on the state of the + * device. For information on whether a specific value is fixed, see the documentation for its key. + * </p> * * <p>When obtained by a client that does not hold the CAMERA permission, some metadata values are * not included. The list of keys that require the permission is given by @@ -281,9 +284,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p>The field definitions can be * found in {@link CameraCharacteristics}.</p> * - * <p>Querying the value for the same key more than once will return a value - * which is equal to the previous queried value.</p> - * * @throws IllegalArgumentException if the key was not valid * * @param key The characteristics field to read. diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 144b1de148b4..73dd50945289 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -152,21 +152,8 @@ public final class CameraManager { mContext.checkSelfPermission(CAMERA_OPEN_CLOSE_LISTENER_PERMISSION) == PackageManager.PERMISSION_GRANTED; } - - mFoldStateListener = new FoldStateListener(context); - try { - context.getSystemService(DeviceStateManager.class).registerCallback( - new HandlerExecutor(CameraManagerGlobal.get().getDeviceStateHandler()), - mFoldStateListener); - } catch (IllegalStateException e) { - Log.v(TAG, "Failed to register device state listener!"); - Log.v(TAG, "Device state dependent characteristics updates will not be functional!"); - mFoldStateListener = null; - } } - private FoldStateListener mFoldStateListener; - /** * @hide */ @@ -228,12 +215,7 @@ public final class CameraManager { * @hide */ public void registerDeviceStateListener(@NonNull CameraCharacteristics chars) { - synchronized (mLock) { - DeviceStateListener listener = chars.getDeviceStateListener(); - if (mFoldStateListener != null) { - mFoldStateListener.addDeviceStateListener(listener); - } - } + CameraManagerGlobal.get().registerDeviceStateListener(chars, mContext); } /** @@ -627,6 +609,21 @@ public final class CameraManager { } /** + * <p>Query the capabilities of a camera device. These capabilities are + * immutable for a given camera.</p> + * + * <p>The value of {@link CameraCharacteristics.SENSOR_ORIENTATION} will change for landscape + * cameras depending on whether overrideToPortrait is enabled. If enabled, these cameras will + * appear to be portrait orientation instead, provided that the override is supported by the + * camera device. Only devices that can be opened by {@link #openCamera} will report a changed + * {@link CameraCharacteristics.SENSOR_ORIENTATION}.</p> + * + * @param cameraId The id of the camera device to query. This could be either a standalone + * camera ID which can be directly opened by {@link #openCamera}, or a physical camera ID that + * can only used as part of a logical multi-camera. + * @param overrideToPortrait Whether to apply the landscape to portrait override. + * @return The properties of the given camera + * * @hide */ @TestApi @@ -1781,6 +1778,7 @@ public final class CameraManager { private HandlerThread mDeviceStateHandlerThread; private Handler mDeviceStateHandler; + private FoldStateListener mFoldStateListener; // Singleton, don't allow construction private CameraManagerGlobal() { } @@ -1795,7 +1793,8 @@ public final class CameraManager { return gCameraManager; } - public Handler getDeviceStateHandler() { + public void registerDeviceStateListener(@NonNull CameraCharacteristics chars, + @NonNull Context ctx) { synchronized(mLock) { if (mDeviceStateHandlerThread == null) { mDeviceStateHandlerThread = new HandlerThread(TAG); @@ -1803,7 +1802,20 @@ public final class CameraManager { mDeviceStateHandler = new Handler(mDeviceStateHandlerThread.getLooper()); } - return mDeviceStateHandler; + if (mFoldStateListener == null) { + mFoldStateListener = new FoldStateListener(ctx); + try { + ctx.getSystemService(DeviceStateManager.class).registerCallback( + new HandlerExecutor(mDeviceStateHandler), mFoldStateListener); + } catch (IllegalStateException e) { + Log.v(TAG, "Failed to register device state listener!"); + Log.v(TAG, "Device state dependent characteristics updates will not be" + + "functional!"); + return; + } + } + + mFoldStateListener.addDeviceStateListener(chars.getDeviceStateListener()); } } diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index a7e28e2f40d1..4950373449e2 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -41,9 +41,10 @@ import java.util.List; * </p> * * <p> - * All instances of CameraMetadata are immutable. The list of keys with {@link #getKeys()} - * never changes, nor do the values returned by any key with {@code #get} throughout - * the lifetime of the object. + * All instances of CameraMetadata are immutable. Beginning with API level 32, the list of keys + * returned by {@link #getKeys()} may change depending on the state of the device, as may the + * values returned by any key with {@code #get} throughout the lifetime of the object. For + * information on whether a specific value is fixed, see the documentation for its key. * </p> * * @see CameraDevice diff --git a/core/java/android/hardware/input/InputDeviceLightsManager.java b/core/java/android/hardware/input/InputDeviceLightsManager.java index f4ee9a21c42c..e2568e3ee72d 100644 --- a/core/java/android/hardware/input/InputDeviceLightsManager.java +++ b/core/java/android/hardware/input/InputDeviceLightsManager.java @@ -18,7 +18,6 @@ package android.hardware.input; import android.annotation.NonNull; import android.app.ActivityThread; -import android.content.Context; import android.hardware.lights.Light; import android.hardware.lights.LightState; import android.hardware.lights.LightsManager; @@ -44,8 +43,7 @@ class InputDeviceLightsManager extends LightsManager { // Package name private final String mPackageName; - InputDeviceLightsManager(Context context, int deviceId) { - super(context); + InputDeviceLightsManager(int deviceId) { mGlobal = InputManagerGlobal.getInstance(); mDeviceId = deviceId; mPackageName = ActivityThread.currentPackageName(); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 8a4a0e40d54a..9cacfff4b33a 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -32,8 +32,6 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.BatteryState; -import android.hardware.SensorManager; -import android.hardware.lights.LightsManager; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -41,7 +39,7 @@ import android.os.InputEventInjectionSync; import android.os.RemoteException; import android.os.SystemClock; import android.os.Vibrator; -import android.os.VibratorManager; +import android.sysprop.InputProperties; import android.util.Log; import android.view.Display; import android.view.InputDevice; @@ -1126,7 +1124,8 @@ public final class InputManager { public boolean isStylusPointerIconEnabled() { if (mIsStylusPointerIconEnabled == null) { mIsStylusPointerIconEnabled = getContext().getResources() - .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon); + .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon) + || InputProperties.force_enable_stylus_pointer_icon().orElse(false); } return mIsStylusPointerIconEnabled; } @@ -1311,47 +1310,6 @@ public final class InputManager { } /** - * Gets a vibrator manager service associated with an input device, always creates a new - * instance. - * @return The vibrator manager, never null. - * @hide - */ - @NonNull - public VibratorManager getInputDeviceVibratorManager(int deviceId) { - return new InputDeviceVibratorManager(deviceId); - } - - /** - * Gets a sensor manager service associated with an input device, always creates a new instance. - * @return The sensor manager, never null. - * @hide - */ - @NonNull - public SensorManager getInputDeviceSensorManager(int deviceId) { - return mGlobal.getInputDeviceSensorManager(deviceId); - } - - /** - * Gets a battery state object associated with an input device, assuming it has one. - * @return The battery, never null. - * @hide - */ - @NonNull - public BatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) { - return mGlobal.getInputDeviceBatteryState(deviceId, hasBattery); - } - - /** - * Gets a lights manager associated with an input device, always creates a new instance. - * @return The lights manager, never null. - * @hide - */ - @NonNull - public LightsManager getInputDeviceLightsManager(int deviceId) { - return new InputDeviceLightsManager(getContext(), deviceId); - } - - /** * Cancel all ongoing pointer gestures on all displays. * @hide */ diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index 31ce7d985b15..701980d5f6f3 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -29,6 +29,7 @@ import android.hardware.input.InputManager.KeyboardBacklightListener; import android.hardware.input.InputManager.OnTabletModeChangedListener; import android.hardware.lights.Light; import android.hardware.lights.LightState; +import android.hardware.lights.LightsManager; import android.hardware.lights.LightsRequest; import android.os.Binder; import android.os.CombinedVibration; @@ -876,7 +877,7 @@ public final class InputManagerGlobal { } /** - * @see InputManager#getInputDeviceSensorManager(int) + * @see InputDevice#getSensorManager() */ @NonNull public SensorManager getInputDeviceSensorManager(int deviceId) { @@ -955,6 +956,14 @@ public final class InputManagerGlobal { } /** + * @see InputDevice#getLightsManager() + */ + @NonNull + public LightsManager getInputDeviceLightsManager(int deviceId) { + return new InputDeviceLightsManager(deviceId); + } + + /** * Gets a list of light objects associated with an input device. * @return The list of lights, never null. */ @@ -1032,7 +1041,7 @@ public final class InputManagerGlobal { } /** - * @see InputManager#getInputDeviceVibratorManager(int) + * @see InputDevice#getVibratorManager() */ @NonNull public VibratorManager getInputDeviceVibratorManager(int deviceId) { @@ -1138,7 +1147,7 @@ public final class InputManagerGlobal { } /** - * @see InputManager#getKeyCodeforKeyLocation(int, int) + * @see InputManager#getKeyCodeForKeyLocation(int, int) */ public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) { try { diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java index 2d9bc0eb14ab..b71b7e05667b 100644 --- a/core/java/android/hardware/lights/LightsManager.java +++ b/core/java/android/hardware/lights/LightsManager.java @@ -25,8 +25,6 @@ import android.content.Context; import android.os.Binder; import android.os.IBinder; -import com.android.internal.util.Preconditions; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -39,7 +37,6 @@ import java.util.List; public abstract class LightsManager { private static final String TAG = "LightsManager"; - @NonNull private final Context mContext; // These enum values copy the values from {@link com.android.server.lights.LightsManager} // and the light HAL. Since 0-7 are lights reserved for system use, only the microphone light // and following types are available through this API. @@ -62,9 +59,7 @@ public abstract class LightsManager { /** * @hide to prevent subclassing from outside of the framework */ - public LightsManager(Context context) { - mContext = Preconditions.checkNotNull(context); - } + public LightsManager() {} /** * Returns the lights available on the device. diff --git a/core/java/android/hardware/lights/SystemLightsManager.java b/core/java/android/hardware/lights/SystemLightsManager.java index 055a7f43f9ed..3beb4ba48e16 100644 --- a/core/java/android/hardware/lights/SystemLightsManager.java +++ b/core/java/android/hardware/lights/SystemLightsManager.java @@ -59,7 +59,6 @@ public final class SystemLightsManager extends LightsManager { */ @VisibleForTesting public SystemLightsManager(@NonNull Context context, @NonNull ILightsManager service) { - super(context); mService = Preconditions.checkNotNull(service); } diff --git a/core/java/android/hardware/soundtrigger/OWNERS b/core/java/android/hardware/soundtrigger/OWNERS index 01b2cb981bbb..1e41886fe716 100644 --- a/core/java/android/hardware/soundtrigger/OWNERS +++ b/core/java/android/hardware/soundtrigger/OWNERS @@ -1,2 +1 @@ -atneya@google.com -elaurent@google.com +include /media/java/android/media/soundtrigger/OWNERS diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 7c2e518b8544..44144d92f56a 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -238,7 +238,7 @@ public class UsbDeviceConnection { * or negative value for failure */ public int controlTransfer(int requestType, int request, int value, - int index, byte[] buffer, int length, int timeout) { + int index, @Nullable byte[] buffer, int length, int timeout) { return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout); } @@ -263,7 +263,7 @@ public class UsbDeviceConnection { * or negative value for failure */ public int controlTransfer(int requestType, int request, int value, int index, - byte[] buffer, int offset, int length, int timeout) { + @Nullable byte[] buffer, int offset, int length, int timeout) { checkBounds(buffer, offset, length); return native_control_request(requestType, request, value, index, buffer, offset, length, timeout); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 104a8b2095d8..efed6883a114 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -780,11 +780,11 @@ public class NetworkPolicyManager { case ActivityManager.PROCESS_STATE_PERSISTENT: case ActivityManager.PROCESS_STATE_PERSISTENT_UI: case ActivityManager.PROCESS_STATE_TOP: - return ActivityManager.PROCESS_CAPABILITY_ALL; case ActivityManager.PROCESS_STATE_BOUND_TOP: case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE: case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE: - return ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; + return ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK + | ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; default: return ActivityManager.PROCESS_CAPABILITY_NONE; } @@ -826,13 +826,18 @@ public class NetworkPolicyManager { if (uidState == null) { return false; } - return isProcStateAllowedWhileOnRestrictBackground(uidState.procState); + return isProcStateAllowedWhileOnRestrictBackground(uidState.procState, uidState.capability); } /** @hide */ - public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) { - // Data saver and bg policy restrictions will only take procstate into account. - return procState <= FOREGROUND_THRESHOLD_STATE; + public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState, + @ProcessCapability int capabilities) { + return procState <= FOREGROUND_THRESHOLD_STATE + // This is meant to be a user-initiated job, and therefore gets similar network + // access to FGS. + || (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + && (capabilities + & ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0); } /** @hide */ diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 38b3174abd4c..46cf0163c0e5 100644 --- a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -354,6 +354,7 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork } /** @hide */ + @Override public Map<Integer, Integer> getCapabilitiesMatchCriteria() { return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria)); } diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java index 9235d0913295..edf2c093bc8b 100644 --- a/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -29,6 +29,7 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Map; import java.util.Objects; /** @@ -307,4 +308,7 @@ public abstract class VcnUnderlyingNetworkTemplate { public int getMinExitDownstreamBandwidthKbps() { return mMinExitDownstreamBandwidthKbps; } + + /** @hide */ + public abstract Map<Integer, Integer> getCapabilitiesMatchCriteria(); } diff --git a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 2544a6d63561..2e6b09f032fb 100644 --- a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -15,6 +15,9 @@ */ package android.net.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; @@ -23,6 +26,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.NetworkCapabilities; +import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; import android.os.PersistableBundle; import android.util.ArraySet; @@ -32,6 +36,7 @@ import com.android.server.vcn.util.PersistableBundleUtils; import java.util.ArrayList; import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -162,6 +167,12 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork return Collections.unmodifiableSet(mSsids); } + /** @hide */ + @Override + public Map<Integer, Integer> getCapabilitiesMatchCriteria() { + return Collections.singletonMap(NET_CAPABILITY_INTERNET, MATCH_REQUIRED); + } + /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */ public static final class Builder { private int mMeteredMatchCriteria = MATCH_ANY; diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index bfc5afe61265..4bfff16d973f 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -8434,7 +8434,7 @@ public final class ContactsContract { extras.putString(KEY_ACCOUNT_NAME, accountName); extras.putString(KEY_ACCOUNT_TYPE, accountType); - contentResolver.call(ContactsContract.AUTHORITY_URI, + nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI, ContactsContract.SimContacts.ADD_SIM_ACCOUNT_METHOD, null, extras); } @@ -8457,7 +8457,7 @@ public final class ContactsContract { Bundle extras = new Bundle(); extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex); - contentResolver.call(ContactsContract.AUTHORITY_URI, + nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI, ContactsContract.SimContacts.REMOVE_SIM_ACCOUNT_METHOD, null, extras); } @@ -8469,7 +8469,7 @@ public final class ContactsContract { */ public static @NonNull List<SimAccount> getSimAccounts( @NonNull ContentResolver contentResolver) { - Bundle response = contentResolver.call(ContactsContract.AUTHORITY_URI, + Bundle response = nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI, ContactsContract.SimContacts.QUERY_SIM_ACCOUNTS_METHOD, null, null); List<SimAccount> result = response.getParcelableArrayList(KEY_SIM_ACCOUNTS, android.provider.ContactsContract.SimAccount.class); @@ -9088,7 +9088,8 @@ public final class ContactsContract { * @param contactId the id of the contact to undemote. */ public static void undemote(ContentResolver contentResolver, long contactId) { - contentResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD, + nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI, + PinnedPositions.UNDEMOTE_METHOD, String.valueOf(contactId), null); } @@ -10300,4 +10301,13 @@ public final class ContactsContract { public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata_sync_state"; } + + private static Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull Uri uri, + @NonNull String method, @Nullable String arg, @Nullable Bundle extras) { + try (ContentProviderClient client = resolver.acquireContentProviderClient(uri)) { + return client.call(method, arg, extras); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5137bc14339f..c473d3f81823 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7113,6 +7113,28 @@ public final class Settings { "input_method_selector_visibility"; /** + * Toggle for enabling stylus handwriting. When enabled, current Input method receives + * stylus {@link MotionEvent}s if an {@link Editor} is focused. + * + * @see #STYLUS_HANDWRITING_DEFAULT_VALUE + * @hide + */ + @TestApi + @Readable + @SuppressLint("NoSettingsProvider") + public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled"; + + /** + * Default value for {@link #STYLUS_HANDWRITING_ENABLED}. + * + * @hide + */ + @TestApi + @Readable + @SuppressLint("NoSettingsProvider") + public static final int STYLUS_HANDWRITING_DEFAULT_VALUE = 1; + + /** * The currently selected voice interaction service flattened ComponentName. * @hide */ @@ -7414,6 +7436,8 @@ public final class Settings { * * @hide */ + @TestApi + @Readable @SuppressLint("NoSettingsProvider") public static final String STYLUS_BUTTONS_ENABLED = "stylus_buttons_enabled"; @@ -11728,13 +11752,14 @@ public final class Settings { public static final String THEATER_MODE_ON = "theater_mode_on"; /** - * Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio. + * Constant for use in AIRPLANE_MODE_RADIOS or SATELLITE_MODE_RADIOS to specify Bluetooth + * radio. */ @Readable public static final String RADIO_BLUETOOTH = "bluetooth"; /** - * Constant for use in AIRPLANE_MODE_RADIOS to specify Wi-Fi radio. + * Constant for use in AIRPLANE_MODE_RADIOS or SATELLITE_MODE_RADIOS to specify Wi-Fi radio. */ @Readable public static final String RADIO_WIFI = "wifi"; @@ -11751,12 +11776,40 @@ public final class Settings { public static final String RADIO_CELL = "cell"; /** - * Constant for use in AIRPLANE_MODE_RADIOS to specify NFC radio. + * Constant for use in AIRPLANE_MODE_RADIOS or SATELLITE_MODE_RADIOS to specify NFC radio. */ @Readable public static final String RADIO_NFC = "nfc"; /** + * Constant for use in SATELLITE_MODE_RADIOS to specify UWB radio. + * + * {@hide} + */ + public static final String RADIO_UWB = "uwb"; + + + /** + * A comma separated list of radios that need to be disabled when satellite mode is on. + * + * {@hide} + */ + public static final String SATELLITE_MODE_RADIOS = "satellite_mode_radios"; + + /** + * The satellite mode is enabled for the user. When the satellite mode is enabled, the + * satellite radio will be turned on and all other radios will be turned off. When the + * satellite mode is disabled, the satellite radio will be turned off and the states of + * other radios will be restored. + * <p> + * When this setting is set to 0, it means the satellite mode is disabled. When this + * setting is set to 1, it means the satellite mode is enabled. + * + * {@hide} + */ + public static final String SATELLITE_MODE_ENABLED = "satellite_mode_enabled"; + + /** * A comma separated list of radios that need to be disabled when airplane mode * is on. This overrides WIFI_ON and BLUETOOTH_ON, if Wi-Fi and bluetooth are * included in the comma separated list. @@ -16451,17 +16504,6 @@ public final class Settings { public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets"; /** - * Toggle for enabling stylus handwriting. When enabled, current Input method receives - * stylus {@link MotionEvent}s if an {@link Editor} is focused. - * - * @hide - */ - @TestApi - @Readable - @SuppressLint("NoSettingsProvider") - public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled"; - - /** * Indicates whether a stylus has ever been used on the device. * * @hide diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java index cc1b6cda82bb..e36d899e02ee 100644 --- a/core/java/android/service/autofill/FillContext.java +++ b/core/java/android/service/autofill/FillContext.java @@ -127,7 +127,7 @@ public final class FillContext implements Parcelable { final int index = missingNodeIndexes.keyAt(i); final AutofillId id = ids[index]; - if (id.equals(node.getAutofillId())) { + if (id != null && id.equals(node.getAutofillId())) { foundNodes[index] = node; if (mViewNodeLookupTable == null) { diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java index 47b75d135813..d2a4a660452c 100644 --- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java +++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java @@ -167,7 +167,8 @@ public final class CredentialProviderInfoFactory { Slog.w(TAG, "Context is null in isSystemProviderWithValidPermission"); return false; } - return PermissionUtils.hasPermission(context, serviceInfo.packageName, + return PermissionUtils.isSystemApp(context, serviceInfo.packageName) + && PermissionUtils.hasPermission(context, serviceInfo.packageName, Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE); } @@ -224,14 +225,6 @@ public final class CredentialProviderInfoFactory { Log.e(TAG, "Failed to get XML metadata", e); } - // 5. Extract the legacy metadata. - try { - builder.addCapabilities( - populateLegacyProviderCapabilities(resources, metadata, serviceInfo)); - } catch (Exception e) { - Log.e(TAG, "Failed to get legacy metadata ", e); - } - return builder; } @@ -325,38 +318,6 @@ public final class CredentialProviderInfoFactory { return capabilities; } - private static Set<String> populateLegacyProviderCapabilities( - Resources resources, Bundle metadata, ServiceInfo serviceInfo) { - Set<String> output = new HashSet<>(); - Set<String> capabilities = new HashSet<>(); - - try { - String[] discovered = - resources.getStringArray( - metadata.getInt(CredentialProviderService.CAPABILITY_META_DATA_KEY)); - if (discovered != null) { - capabilities.addAll(Arrays.asList(discovered)); - } - } catch (Resources.NotFoundException | NullPointerException e) { - Log.e(TAG, "Failed to get capabilities: ", e); - } - - if (capabilities.size() == 0) { - Log.e(TAG, "No capabilities found for provider:" + serviceInfo); - return output; - } - - for (String capability : capabilities) { - if (capability == null || capability.isEmpty()) { - Log.w(TAG, "Skipping empty/null capability"); - continue; - } - Log.i(TAG, "Capabilities found for provider: " + capability); - output.add(capability); - } - return output; - } - private static ServiceInfo getServiceInfoOrThrow( @NonNull ComponentName serviceComponent, int userId) throws PackageManager.NameNotFoundException { diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java index 6824159706cd..b97760656059 100644 --- a/core/java/android/service/credentials/CredentialProviderService.java +++ b/core/java/android/service/credentials/CredentialProviderService.java @@ -156,14 +156,6 @@ public abstract class CredentialProviderService extends Service { private static final String TAG = "CredProviderService"; - /** - * The list of capabilities exposed by a credential provider. - * - * @deprecated Replaced with {@link android.service.credentials#SERVICE_META_DATA} - */ - @Deprecated - public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities"; - /** * Name under which a Credential Provider service component publishes information * about itself. This meta-data must reference an XML resource containing diff --git a/core/java/android/service/credentials/PermissionUtils.java b/core/java/android/service/credentials/PermissionUtils.java index c8bb202c35f7..d958111f2e0e 100644 --- a/core/java/android/service/credentials/PermissionUtils.java +++ b/core/java/android/service/credentials/PermissionUtils.java @@ -30,16 +30,19 @@ public class PermissionUtils { /** Checks whether the given package name hold the given permission **/ public static boolean hasPermission(Context context, String packageName, String permission) { + return context.getPackageManager().checkPermission(permission, packageName) + == PackageManager.PERMISSION_GRANTED; + } + + /** Checks whether the given package name is a system app on the device **/ + public static boolean isSystemApp(Context context, String packageName) { try { ApplicationInfo appInfo = context.getPackageManager() - .getApplicationInfo( - packageName, + .getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of( PackageManager.MATCH_SYSTEM_ONLY)); - if (appInfo != null - && context.checkPermission(permission, /* pid= */ -1, appInfo.uid) - == PackageManager.PERMISSION_GRANTED) { + if (appInfo != null) { return true; } } catch (PackageManager.NameNotFoundException e) { diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index bc514b091409..c3295088ef11 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -234,8 +234,8 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "true"); DEFAULT_FLAGS.put(SETTINGS_FLASH_NOTIFICATIONS, "true"); DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "true"); - DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "false"); - DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "false"); + DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "true"); + DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "true"); } private static final Set<String> PERSISTENT_FLAGS; diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index e81aecb23c24..48fb719279d5 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -28,7 +28,6 @@ import android.hardware.BatteryState; import android.hardware.SensorManager; import android.hardware.input.HostUsiVersion; import android.hardware.input.InputDeviceIdentifier; -import android.hardware.input.InputManager; import android.hardware.input.InputManagerGlobal; import android.hardware.lights.LightsManager; import android.icu.util.ULocale; @@ -1191,7 +1190,8 @@ public final class InputDevice implements Parcelable { public LightsManager getLightsManager() { synchronized (mMotionRanges) { if (mLightsManager == null) { - mLightsManager = InputManager.getInstance().getInputDeviceLightsManager(mId); + mLightsManager = InputManagerGlobal.getInstance() + .getInputDeviceLightsManager(mId); } } return mLightsManager; diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 16bc155caadd..bd249c42031d 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -63,37 +63,6 @@ import java.util.StringJoiner; */ public class InsetsState implements Parcelable { - /** - * Internal representation of inset source types. This is different from the public API in - * {@link WindowInsets.Type} as one type from the public API might indicate multiple windows - * at the same time. - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "ITYPE", value = { - ITYPE_CAPTION_BAR, - ITYPE_LEFT_TAPPABLE_ELEMENT, - ITYPE_TOP_TAPPABLE_ELEMENT, - ITYPE_RIGHT_TAPPABLE_ELEMENT, - ITYPE_BOTTOM_TAPPABLE_ELEMENT, - ITYPE_LEFT_GENERIC_OVERLAY, - ITYPE_TOP_GENERIC_OVERLAY, - ITYPE_RIGHT_GENERIC_OVERLAY, - ITYPE_BOTTOM_GENERIC_OVERLAY - }) - public @interface InternalInsetsType {} - - public static final int ITYPE_CAPTION_BAR = 0; - - public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 1; - public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 2; - public static final int ITYPE_RIGHT_TAPPABLE_ELEMENT = 3; - public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 4; - - public static final int ITYPE_LEFT_GENERIC_OVERLAY = 5; - public static final int ITYPE_TOP_GENERIC_OVERLAY = 6; - public static final int ITYPE_RIGHT_GENERIC_OVERLAY = 7; - public static final int ITYPE_BOTTOM_GENERIC_OVERLAY = 8; - @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "ISIDE", value = { ISIDE_LEFT, @@ -677,30 +646,6 @@ public class InsetsState implements Parcelable { && !WindowConfiguration.inMultiWindowMode(windowingMode); } - /** - * Converting a internal type to the public type. - * @param type internal insets type, {@code InternalInsetsType}. - * @return public insets type, {@code Type.InsetsType}. - */ - public static @Type.InsetsType int toPublicType(@InternalInsetsType int type) { - switch (type) { - case ITYPE_LEFT_GENERIC_OVERLAY: - case ITYPE_TOP_GENERIC_OVERLAY: - case ITYPE_RIGHT_GENERIC_OVERLAY: - case ITYPE_BOTTOM_GENERIC_OVERLAY: - return Type.SYSTEM_OVERLAYS; - case ITYPE_CAPTION_BAR: - return Type.CAPTION_BAR; - case ITYPE_LEFT_TAPPABLE_ELEMENT: - case ITYPE_TOP_TAPPABLE_ELEMENT: - case ITYPE_RIGHT_TAPPABLE_ELEMENT: - case ITYPE_BOTTOM_TAPPABLE_ELEMENT: - return Type.TAPPABLE_ELEMENT; - default: - throw new IllegalArgumentException("Unknown type: " + type); - } - } - public void dump(String prefix, PrintWriter pw) { final String newPrefix = prefix + " "; pw.println(prefix + "InsetsState"); diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 2af025469df4..b6d9400fad5c 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -897,13 +897,38 @@ public class KeyEvent extends InputEvent implements Parcelable { * This key is handled by the framework and is never delivered to applications. */ public static final int KEYCODE_RECENT_APPS = 312; + /** + * Key code constant: A button whose usage can be customized by the user through + * the system. + * User customizable key #1. + */ + public static final int KEYCODE_MACRO_1 = 313; + /** + * Key code constant: A button whose usage can be customized by the user through + * the system. + * User customizable key #2. + */ + public static final int KEYCODE_MACRO_2 = 314; + /** + * Key code constant: A button whose usage can be customized by the user through + * the system. + * User customizable key #3. + */ + public static final int KEYCODE_MACRO_3 = 315; + /** + * Key code constant: A button whose usage can be customized by the user through + * the system. + * User customizable key #4. + */ + public static final int KEYCODE_MACRO_4 = 316; + /** * Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent. * @hide */ @TestApi - public static final int LAST_KEYCODE = KEYCODE_RECENT_APPS; + public static final int LAST_KEYCODE = KEYCODE_MACRO_4; // NOTE: If you add a new keycode here you must also add it to: // isSystem() diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 6a493e6c6ff1..d88994b7296e 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -57,8 +57,9 @@ public final class PointerIcon implements Parcelable { /** Type constant: Null icon. It has no bitmap. */ public static final int TYPE_NULL = 0; - /** Type constant: no icons are specified. If all views uses this, then falls back - * to the default type, but this is helpful to distinguish a view explicitly want + /** + * Type constant: no icons are specified. If all views uses this, then the pointer icon falls + * back to the default type, but this is helpful to distinguish a view that explicitly wants * to have the default icon. * @hide */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6cd894113ca6..003307db832a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -92,6 +92,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.hardware.display.DisplayManagerGlobal; +import android.hardware.input.InputManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -5413,7 +5414,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * The pointer icon when the mouse hovers on this view. The default is null. */ - private PointerIcon mPointerIcon; + private PointerIcon mMousePointerIcon; /** * @hide @@ -29506,30 +29507,71 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. - * The default implementation does not care the location or event types, but some subclasses - * may use it (such as WebViews). - * @param event The MotionEvent from a mouse - * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. - * This will be between 0 and {@link MotionEvent#getPointerCount()}. + * Resolve the pointer icon that should be used for specified pointer in the motion event. + * + * The default implementation will resolve the pointer icon to one set using + * {@link #setPointerIcon(PointerIcon)} for mouse devices. Subclasses may override this to + * customize the icon for the given pointer. + * + * For example, the pointer icon for a stylus pointer can be resolved in the following way: + * <code><pre> + * @Override + * public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { + * final int toolType = event.getToolType(pointerIndex); + * if (!event.isFromSource(InputDevice.SOURCE_MOUSE) + * && event.isFromSource(InputDevice.SOURCE_STYLUS) + * && (toolType == MotionEvent.TOOL_TYPE_STYLUS + * || toolType == MotionEvent.TOOL_TYPE_ERASER)) { + * // Show this pointer icon only if this pointer is a stylus. + * return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_WAIT); + * } + * // Use the default logic for determining the pointer icon for other non-stylus pointers, + * // like for the mouse cursor. + * return super.onResolvePointerIcon(event, pointerIndex); + * } + * </pre></code> + * + * @param event The {@link MotionEvent} that requires a pointer icon to be resolved for one of + * pointers. + * @param pointerIndex The index of the pointer in {@code event} for which to retrieve the + * {@link PointerIcon}. This will be between 0 and {@link MotionEvent#getPointerCount()}. + * @return the pointer icon to use for specified pointer, or {@code null} if a pointer icon + * is not specified and the default icon should be used. * @see PointerIcon + * @see InputManager#isStylusPointerIconEnabled() */ public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { final float x = event.getX(pointerIndex); final float y = event.getY(pointerIndex); if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { - return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); + // Use the default pointer icon. + return null; + } + + // Note: A drawing tablet will have both SOURCE_MOUSE and SOURCE_STYLUS, but it would use + // TOOL_TYPE_STYLUS. For now, treat drawing tablets the same way as a mouse or touchpad. + if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { + return mMousePointerIcon; } - return mPointerIcon; + + return null; } /** - * Set the pointer icon for the current view. + * Set the pointer icon to be used for a mouse pointer in the current view. + * * Passing {@code null} will restore the pointer icon to its default value. + * Note that setting the pointer icon using this method will only set it for events coming from + * a mouse device (i.e. with source {@link InputDevice#SOURCE_MOUSE}). To resolve + * the pointer icon for other device types like styluses, override + * {@link #onResolvePointerIcon(MotionEvent, int)}. + * * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. + * @see #onResolvePointerIcon(MotionEvent, int) + * @see PointerIcon */ public void setPointerIcon(PointerIcon pointerIcon) { - mPointerIcon = pointerIcon; + mMousePointerIcon = pointerIcon; if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { return; } @@ -29540,11 +29582,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Gets the pointer icon for the current view. + * Gets the mouse pointer icon for the current view. + * + * @see #setPointerIcon(PointerIcon) */ @InspectableProperty public PointerIcon getPointerIcon() { - return mPointerIcon; + return mMousePointerIcon; } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 46ae3ea21890..f5e4da86bfea 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -66,6 +66,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.LayoutAnimationController; import android.view.animation.Transformation; import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; import android.view.autofill.Helper; import android.view.inspector.InspectableProperty; import android.view.inspector.InspectableProperty.EnumEntry; @@ -3709,6 +3710,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return children; } + private AutofillManager getAutofillManager() { + return mContext.getSystemService(AutofillManager.class); + } + + private boolean shouldIncludeAllChildrenViewWithAutofillTypeNotNone(AutofillManager afm) { + if (afm == null) return false; + return afm.shouldIncludeAllChildrenViewsWithAutofillTypeNotNoneInAssistStructure(); + } + + private boolean shouldIncludeAllChildrenViews(AutofillManager afm){ + if (afm == null) return false; + return afm.shouldIncludeAllChildrenViewInAssistStructure(); + } + /** @hide */ private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) { final int childrenCount = mChildrenCount; @@ -3718,6 +3733,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final ArrayList<View> preorderedList = buildOrderedChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); + final AutofillManager afm = getAutofillManager(); for (int i = 0; i < childrenCount; i++) { final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View child = (preorderedList == null) @@ -3725,7 +3741,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if ((flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 || child.isImportantForAutofill() || (child.isMatchingAutofillableHeuristics() - && !child.isActivityDeniedForAutofillForUnimportantView())) { + && !child.isActivityDeniedForAutofillForUnimportantView()) + || (shouldIncludeAllChildrenViewWithAutofillTypeNotNone(afm) + && child.getAutofillType() != AUTOFILL_TYPE_NONE) + || shouldIncludeAllChildrenViews(afm)){ list.add(child); } else if (child instanceof ViewGroup) { ((ViewGroup) child).populateChildrenForAutofill(list, flags); diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java index b74b80eeec2c..7ad43c76efaa 100644 --- a/core/java/android/view/WindowMetrics.java +++ b/core/java/android/view/WindowMetrics.java @@ -162,7 +162,7 @@ public final class WindowMetrics { return WindowMetrics.class.getSimpleName() + ":{" + "bounds=" + mBounds + ", windowInsets=" + mWindowInsets - + ", density" + mDensity + + ", density=" + mDensity + "}"; } } diff --git a/core/java/android/view/autofill/AutofillClientController.java b/core/java/android/view/autofill/AutofillClientController.java index 93d98ac51c3b..3a8e8027b88e 100644 --- a/core/java/android/view/autofill/AutofillClientController.java +++ b/core/java/android/view/autofill/AutofillClientController.java @@ -350,6 +350,10 @@ public final class AutofillClientController implements AutofillManager.AutofillC final boolean[] visible = new boolean[autofillIdCount]; for (int i = 0; i < autofillIdCount; i++) { final AutofillId autofillId = autofillIds[i]; + if (autofillId == null) { + visible[i] = false; + continue; + } final View view = autofillClientFindViewByAutofillIdTraversal(autofillId); if (view != null) { if (!autofillId.isVirtualInt()) { @@ -383,6 +387,7 @@ public final class AutofillClientController implements AutofillManager.AutofillC @Override public View autofillClientFindViewByAutofillIdTraversal(AutofillId autofillId) { + if (autofillId == null) return null; final ArrayList<ViewRootImpl> roots = WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken()); for (int rootNum = 0; rootNum < roots.size(); rootNum++) { @@ -410,7 +415,7 @@ public final class AutofillClientController implements AutofillManager.AutofillC if (rootView != null) { final int viewCount = autofillIds.length; for (int viewNum = 0; viewNum < viewCount; viewNum++) { - if (views[viewNum] == null) { + if (autofillIds[viewNum] != null && views[viewNum] == null) { views[viewNum] = rootView.findViewByAutofillIdTraversal( autofillIds[viewNum].getViewId()); } diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java index e267a7f1e248..4aa612c526fe 100644 --- a/core/java/android/view/autofill/AutofillFeatureFlags.java +++ b/core/java/android/view/autofill/AutofillFeatureFlags.java @@ -150,6 +150,15 @@ public class AutofillFeatureFlags { "package_deny_list_for_unimportant_view"; /** + * Sets the list of activities and packages allowed for autofill. The format is same with + * {@link #DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW} + * + * @hide + */ + public static final String DEVICE_CONFIG_PACKAGE_AND_ACTIVITY_ALLOWLIST_FOR_TRIGGERING_FILL_REQUEST = + "package_and_activity_allowlist_for_triggering_fill_request"; + + /** * Whether the heuristics check for view is enabled */ public static final String DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_UNIMPORTANT_VIEW = @@ -183,6 +192,25 @@ public class AutofillFeatureFlags { */ public static final String DEVICE_CONFIG_SHOULD_ENABLE_AUTOFILL_ON_ALL_VIEW_TYPES = "should_enable_autofill_on_all_view_types"; + + /** + * Whether include all autofill type not none views in assist structure + * + * @hide + */ + public static final String + DEVICE_CONFIG_INCLUDE_ALL_AUTOFILL_TYPE_NOT_NONE_VIEWS_IN_ASSIST_STRUCTURE = + "include_all_autofill_type_not_none_views_in_assist_structure"; + + /** + * Whether include all views in assist structure + * + * @hide + */ + public static final String + DEVICE_CONFIG_INCLUDE_ALL_VIEWS_IN_ASSIST_STRUCTURE = + "include_all_views_in_assist_structure"; + // END AUTOFILL FOR ALL APPS FLAGS // @@ -378,6 +406,38 @@ public class AutofillFeatureFlags { DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW, ""); } + /** + * Get autofill allowlist from flag + * + * @hide + */ + public static String getAllowlistStringFromFlag() { + return DeviceConfig.getString( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_PACKAGE_AND_ACTIVITY_ALLOWLIST_FOR_TRIGGERING_FILL_REQUEST, ""); + } + /** + * Whether include all views that have autofill type not none in assist structure. + * + * @hide + */ + public static boolean shouldIncludeAllViewsAutofillTypeNotNoneInAssistStructrue() { + return DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_INCLUDE_ALL_AUTOFILL_TYPE_NOT_NONE_VIEWS_IN_ASSIST_STRUCTURE, false); + } + + /** + * Whether include all views in assist structure. + * + * @hide + */ + public static boolean shouldIncludeAllChildrenViewInAssistStructure() { + return DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_INCLUDE_ALL_VIEWS_IN_ASSIST_STRUCTURE, false); + } + // START AUTOFILL PCC CLASSIFICATION FUNCTIONS diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index c5befb6f418f..801b13a2c69c 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -694,7 +694,24 @@ public final class AutofillManager { private boolean mIsPackagePartiallyDeniedForAutofill = false; // A deny set read from device config - private Set<String> mDeniedActivitiySet = new ArraySet<>(); + private Set<String> mDeniedActivitySet = new ArraySet<>(); + + // If a package is fully allowed, all views in package will skip the heuristic check + private boolean mIsPackageFullyAllowedForAutofill = false; + + // If a package is partially denied, autofill manager will check whether + // current activity is in allowed activity set. If it's allowed activity, then autofill manager + // will skip the heuristic check + private boolean mIsPackagePartiallyAllowedForAutofill = false; + + // An allowed activity set read from device config + private Set<String> mAllowedActivitySet = new ArraySet<>(); + + // Indicate whether should include all view with autofill type not none in assist structure + private boolean mShouldIncludeAllViewsWithAutofillTypeNotNoneInAssistStructure; + + // Indicate whether should include all view in assist structure + private boolean mShouldIncludeAllChildrenViewInAssistStructure; // Indicates whether called the showAutofillDialog() method. private boolean mShowAutofillDialogCalled = false; @@ -873,20 +890,41 @@ public final class AutofillManager { AutofillFeatureFlags.getNonAutofillableImeActionIdSetFromFlag(); final String denyListString = AutofillFeatureFlags.getDenylistStringFromFlag(); + final String allowlistString = AutofillFeatureFlags.getAllowlistStringFromFlag(); final String packageName = mContext.getPackageName(); mIsPackageFullyDeniedForAutofill = - isPackageFullyDeniedForAutofill(denyListString, packageName); + isPackageFullyAllowedOrDeniedForAutofill(denyListString, packageName); + + mIsPackageFullyAllowedForAutofill = + isPackageFullyAllowedOrDeniedForAutofill(allowlistString, packageName); if (!mIsPackageFullyDeniedForAutofill) { mIsPackagePartiallyDeniedForAutofill = - isPackagePartiallyDeniedForAutofill(denyListString, packageName); + isPackagePartiallyDeniedOrAllowedForAutofill(denyListString, packageName); + } + + if (!mIsPackageFullyAllowedForAutofill) { + mIsPackagePartiallyAllowedForAutofill = + isPackagePartiallyDeniedOrAllowedForAutofill(allowlistString, packageName); } if (mIsPackagePartiallyDeniedForAutofill) { - setDeniedActivitySetWithDenyList(denyListString, packageName); + mDeniedActivitySet = getDeniedOrAllowedActivitySetFromString( + denyListString, packageName); } + + if (mIsPackagePartiallyAllowedForAutofill) { + mAllowedActivitySet = getDeniedOrAllowedActivitySetFromString( + allowlistString, packageName); + } + + mShouldIncludeAllViewsWithAutofillTypeNotNoneInAssistStructure + = AutofillFeatureFlags.shouldIncludeAllViewsAutofillTypeNotNoneInAssistStructrue(); + + mShouldIncludeAllChildrenViewInAssistStructure + = AutofillFeatureFlags.shouldIncludeAllChildrenViewInAssistStructure(); } /** @@ -921,59 +959,73 @@ public final class AutofillManager { return true; } - private boolean isPackageFullyDeniedForAutofill( - @NonNull String denyListString, @NonNull String packageName) { - // If "PackageName:;" is in the string, then it means the package name is in denylist - // and there are no activities specified under it. That means the package is fully - // denied for autofill - return denyListString.indexOf(packageName + ":;") != -1; + private boolean isPackageFullyAllowedOrDeniedForAutofill( + @NonNull String listString, @NonNull String packageName) { + // If "PackageName:;" is in the string, then it the package is fully denied or allowed for + // autofill, depending on which string is passed to this function + return listString.indexOf(packageName + ":;") != -1; } - private boolean isPackagePartiallyDeniedForAutofill( - @NonNull String denyListString, @NonNull String packageName) { - // This check happens after checking package is not fully denied. If "PackageName:" instead - // is in denylist, then it means there are specific activities to be denied. So the package - // is partially denied for autofill - return denyListString.indexOf(packageName + ":") != -1; + private boolean isPackagePartiallyDeniedOrAllowedForAutofill( + @NonNull String listString, @NonNull String packageName) { + // If "PackageName:" is in string when "PackageName:;" is not, then it means there are + // specific activities to be allowed or denied. So the package is partially allowed or + // denied for autofill. + return listString.indexOf(packageName + ":") != -1; } /** - * Get the denied activitiy names under specified package from denylist and set it in field - * mDeniedActivitiySet + * @hide + */ + public boolean shouldIncludeAllChildrenViewsWithAutofillTypeNotNoneInAssistStructure() { + return mShouldIncludeAllViewsWithAutofillTypeNotNoneInAssistStructure; + } + + /** + * @hide + */ + public boolean shouldIncludeAllChildrenViewInAssistStructure() { + return mShouldIncludeAllChildrenViewInAssistStructure; + } + + /** + * Get the denied or allowed activitiy names under specified package from the list string and + * set it in fields accordingly * - * If using parameter as the example below, the denied activity set would be set to - * Set{Activity1,Activity2}. + * For example, if the package name is Package1, and the string is + * "Package1:Activity1,Activity2;", then the extracted activity set would be + * {Activity1, Activity2} * - * @param denyListString Denylist that is got from device config. For example, + * @param listString Denylist that is got from device config. For example, * "Package1:Activity1,Activity2;Package2:;" - * @param packageName Specify to extract activities under which package.For example, - * "Package1:;" + * @param packageName Specify which package to extract.For example, "Package1" + * + * @return the extracted activity set, For example, {Activity1, Activity2} */ - private void setDeniedActivitySetWithDenyList( - @NonNull String denyListString, @NonNull String packageName) { + private Set<String> getDeniedOrAllowedActivitySetFromString( + @NonNull String listString, @NonNull String packageName) { // 1. Get the index of where the Package name starts - final int packageInStringIndex = denyListString.indexOf(packageName + ":"); + final int packageInStringIndex = listString.indexOf(packageName + ":"); // 2. Get the ";" index after this index of package - final int firstNextSemicolonIndex = denyListString.indexOf(";", packageInStringIndex); + final int firstNextSemicolonIndex = listString.indexOf(";", packageInStringIndex); // 3. Get the activity names substring between the indexes final int activityStringStartIndex = packageInStringIndex + packageName.length() + 1; + if (activityStringStartIndex >= firstNextSemicolonIndex) { - Log.e(TAG, "Failed to get denied activity names from denylist because it's wrongly " + Log.e(TAG, "Failed to get denied activity names from list because it's wrongly " + "formatted"); - return; + return new ArraySet<>(); } final String activitySubstring = - denyListString.substring(activityStringStartIndex, firstNextSemicolonIndex); + listString.substring(activityStringStartIndex, firstNextSemicolonIndex); // 4. Split the activity name substring final String[] activityStringArray = activitySubstring.split(","); - // 5. Set the denied activity set - mDeniedActivitiySet = new ArraySet<>(Arrays.asList(activityStringArray)); - - return; + // 5. return the extracted activities in a set + return new ArraySet<>(Arrays.asList(activityStringArray)); } /** @@ -992,7 +1044,32 @@ public final class AutofillManager { return false; } final ComponentName clientActivity = client.autofillClientGetComponentName(); - if (mDeniedActivitiySet.contains(clientActivity.flattenToShortString())) { + if (mDeniedActivitySet.contains(clientActivity.flattenToShortString())) { + return true; + } + } + return false; + } + + /** + * Check whether current activity is allowlisted for autofill. + * + * If it is, the view in current activity will bypass heuristic check when checking whether it's + * autofillable + * + * @hide + */ + public boolean isActivityAllowedForAutofill() { + if (mIsPackageFullyAllowedForAutofill) { + return true; + } + if (mIsPackagePartiallyAllowedForAutofill) { + final AutofillClient client = getClient(); + if (client == null) { + return false; + } + final ComponentName clientActivity = client.autofillClientGetComponentName(); + if (mAllowedActivitySet.contains(clientActivity.flattenToShortString())) { return true; } } @@ -1009,17 +1086,22 @@ public final class AutofillManager { * @hide */ public boolean isAutofillable(View view) { - if (isActivityDeniedForAutofill()) { - Log.d(TAG, "view is not autofillable - activity denied for autofill"); - return false; - } - // Duplicate the autofill type check here because ViewGroup will call this function to // decide whether to include view in assist structure. // Also keep the autofill type check inside View#IsAutofillable() to serve as an early out // or if other functions need to call it. if (view.getAutofillType() == View.AUTOFILL_TYPE_NONE) return false; + if (isActivityDeniedForAutofill()) { + Log.d(TAG, "view is not autofillable - activity denied for autofill"); + return false; + } + + if (isActivityAllowedForAutofill()) { + Log.d(TAG, "view is autofillable - activity allowed for autofill"); + return true; + } + if (view instanceof EditText) { return isPassingImeActionCheck((EditText) view); } @@ -1037,7 +1119,7 @@ public final class AutofillManager { || view instanceof RadioGroup) { return true; } - + Log.d(TAG, "view is not autofillable - not important and filtered by view type check"); return false; } @@ -2240,7 +2322,10 @@ public final class AutofillManager { * * @param executor specifies the thread upon which the callbacks will be invoked. * @param callback which handles autofill request to provide client's suggestions. + * + * @hide */ + @TestApi @RequiresPermission(PROVIDE_OWN_AUTOFILL_SUGGESTIONS) public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor, @NonNull AutofillRequestCallback callback) { @@ -2257,7 +2342,10 @@ public final class AutofillManager { /** * clears the client's suggestions callback for autofill. + * + * @hide */ + @TestApi public void clearAutofillRequestCallback() { synchronized (mLock) { mRequestCallbackExecutor = null; diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java index e632a5849471..10a088b4ebfa 100644 --- a/core/java/android/view/autofill/AutofillRequestCallback.java +++ b/core/java/android/view/autofill/AutofillRequestCallback.java @@ -18,6 +18,7 @@ package android.view.autofill; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.os.CancellationSignal; import android.service.autofill.FillCallback; import android.view.inputmethod.InlineSuggestionsRequest; @@ -55,7 +56,10 @@ import android.view.inputmethod.InlineSuggestionsRequest; * * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or * the keyboard may choose to block your app from the inline strip. + * + * @hide */ +@TestApi public interface AutofillRequestCallback { /** * Called by the Android system to decide if a screen can be autofilled by the callback. diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java index d84acc03826b..ce2c18080b91 100644 --- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java +++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java @@ -508,6 +508,7 @@ final class IInputMethodManagerGlobalInvoker { @AnyThread static void prepareStylusHandwritingDelegation( @NonNull IInputMethodClient client, + @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName) { final IInputMethodManager service = getService(); @@ -516,7 +517,7 @@ final class IInputMethodManagerGlobalInvoker { } try { service.prepareStylusHandwritingDelegation( - client, delegatePackageName, delegatorPackageName); + client, userId, delegatePackageName, delegatorPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -525,6 +526,7 @@ final class IInputMethodManagerGlobalInvoker { @AnyThread static boolean acceptStylusHandwritingDelegation( @NonNull IInputMethodClient client, + @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName) { final IInputMethodManager service = getService(); @@ -533,7 +535,7 @@ final class IInputMethodManagerGlobalInvoker { } try { return service.acceptStylusHandwritingDelegation( - client, delegatePackageName, delegatorPackageName); + client, userId, delegatePackageName, delegatorPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java index 70279cc8e845..77a2b5b877be 100644 --- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java +++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java @@ -18,6 +18,7 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.app.ActivityThread; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; @@ -700,7 +701,10 @@ public final class InlineSuggestionsRequest implements Parcelable { * provides the input view. * * Note: The default value is {@code true}. + * + * @hide */ + @TestApi @DataClass.Generated.Member public @NonNull Builder setServiceSupported(boolean value) { checkNotUsed(); @@ -714,7 +718,10 @@ public final class InlineSuggestionsRequest implements Parcelable { * input view. * * Note: The default value is {@code true}. + * + * @hide */ + @TestApi @DataClass.Generated.Member public @NonNull Builder setClientSupported(boolean value) { checkNotUsed(); diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 36d2b8a89779..515b95cd951d 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1553,9 +1553,7 @@ public final class InputMethodManager { if (fallbackContext == null) { return false; } - if (!isStylusHandwritingEnabled(fallbackContext)) { - return false; - } + return IInputMethodManagerGlobalInvoker.isStylusHandwritingAvailableAsUser(userId); } @@ -2244,11 +2242,6 @@ public final class InputMethodManager { } boolean useDelegation = !TextUtils.isEmpty(delegatorPackageName); - if (!isStylusHandwritingEnabled(view.getContext())) { - Log.w(TAG, "Stylus handwriting pref is disabled. " - + "Ignoring calls to start stylus handwriting."); - return false; - } checkFocus(); synchronized (mH) { @@ -2264,7 +2257,8 @@ public final class InputMethodManager { } if (useDelegation) { return IInputMethodManagerGlobalInvoker.acceptStylusHandwritingDelegation( - mClient, view.getContext().getOpPackageName(), delegatorPackageName); + mClient, UserHandle.myUserId(), view.getContext().getOpPackageName(), + delegatorPackageName); } else { IInputMethodManagerGlobalInvoker.startStylusHandwriting(mClient); } @@ -2272,15 +2266,6 @@ public final class InputMethodManager { } } - private boolean isStylusHandwritingEnabled(@NonNull Context context) { - if (Settings.Global.getInt(context.getContentResolver(), - Settings.Global.STYLUS_HANDWRITING_ENABLED, 0) == 0) { - Log.d(TAG, "Stylus handwriting pref is disabled."); - return false; - } - return true; - } - /** * Prepares delegation of starting stylus handwriting session to a different editor in same * or different window than the view on which initial handwriting stroke was detected. @@ -2344,13 +2329,9 @@ public final class InputMethodManager { fallbackImm.prepareStylusHandwritingDelegation(delegatorView, delegatePackageName); } - if (!isStylusHandwritingEnabled(delegatorView.getContext())) { - Log.w(TAG, "Stylus handwriting pref is disabled. " - + "Ignoring prepareStylusHandwritingDelegation()."); - return; - } IInputMethodManagerGlobalInvoker.prepareStylusHandwritingDelegation( mClient, + UserHandle.myUserId(), delegatePackageName, delegatorView.getContext().getOpPackageName()); } diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java index eb91d08dc278..ec50c697ae9a 100644 --- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java +++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java @@ -405,21 +405,15 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { } if (handler.getLooper().isCurrentThread()) { servedView.onInputConnectionClosedInternal(); - final ViewRootImpl viewRoot = servedView.getViewRootImpl(); - if (viewRoot != null) { - viewRoot.getHandwritingInitiator().onInputConnectionClosed(servedView); - } } else { handler.post(servedView::onInputConnectionClosedInternal); - handler.post(() -> { - final ViewRootImpl viewRoot = servedView.getViewRootImpl(); - if (viewRoot != null) { - viewRoot.getHandwritingInitiator() - .onInputConnectionClosed(servedView); - } - }); } } + + final ViewRootImpl viewRoot = servedView.getViewRootImpl(); + if (viewRoot != null) { + viewRoot.getHandwritingInitiator().onInputConnectionClosed(servedView); + } } }); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 0bbaac0fa987..6523fffc4b91 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2000,8 +2000,19 @@ public class WebView extends AbsoluteLayout * in order to facilitate debugging of web layouts and JavaScript * code running inside WebViews. Please refer to WebView documentation * for the debugging guide. - * - * The default is {@code false}. + * <p> + * In WebView 113.0.5656.0 and later, this is enabled automatically if the + * app is declared as + * <a href="https://developer.android.com/guide/topics/manifest/application-element#debug"> + * {@code android:debuggable="true"}</a> in its manifest; otherwise, the + * default is {@code false}. + * <p> + * Enabling web contents debugging allows the state of any WebView in the + * app to be inspected and modified by the user via adb. This is a security + * liability and should not be enabled in production builds of apps unless + * this is an explicitly intended use of the app. More info on + * <a href="https://developer.android.com/topic/security/risks/android-debuggable"> + * secure debug settings</a>. * * @param enabled whether to enable web contents debugging */ diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index fd80981fe4b8..d56a06fbd127 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -4604,7 +4604,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private void setTextSizeInternal(int unit, float size, boolean shouldRequestLayout) { + @NonNull + private DisplayMetrics getDisplayMetricsOrSystem() { Context c = getContext(); Resources r; @@ -4614,8 +4615,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener r = c.getResources(); } + return r.getDisplayMetrics(); + } + + private void setTextSizeInternal(int unit, float size, boolean shouldRequestLayout) { mTextSizeUnit = unit; - setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()), + setRawTextSize(TypedValue.applyDimension(unit, size, getDisplayMetricsOrSystem()), shouldRequestLayout); } @@ -6197,10 +6202,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ @android.view.RemotableViewMethod public void setLineHeight(@Px @IntRange(from = 0) int lineHeight) { - Preconditions.checkArgumentNonnegative(lineHeight); + setLineHeightPx(lineHeight); + } + + private void setLineHeightPx(@Px @FloatRange(from = 0) float lineHeight) { + Preconditions.checkArgumentNonnegative((int) lineHeight); final int fontHeight = getPaint().getFontMetricsInt(null); // Make sure we don't setLineSpacing if it's not needed to avoid unnecessary redraw. + // TODO(b/274974975): should this also check if lineSpacing needs to change? if (lineHeight != fontHeight) { // Set lineSpacingExtra by the difference of lineSpacing with lineHeight setLineSpacing(lineHeight - fontHeight, 1f); @@ -6208,6 +6218,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Sets an explicit line height to a given unit and value for this TextView. This is equivalent + * to the vertical distance between subsequent baselines in the TextView. See {@link + * TypedValue} for the possible dimension units. + * + * @param unit The desired dimension unit. SP units are strongly recommended so that line height + * stays proportional to the text size when fonts are scaled up for accessibility. + * @param lineHeight The desired line height in the given units. + * + * @see #setLineSpacing(float, float) + * @see #getLineSpacingExtra() + * + * @attr ref android.R.styleable#TextView_lineHeight + */ + @android.view.RemotableViewMethod + public void setLineHeight(int unit, @FloatRange(from = 0) float lineHeight) { + setLineHeightPx( + TypedValue.applyDimension(unit, lineHeight, getDisplayMetricsOrSystem())); + } + + /** * Set Highlights * * @param highlights A highlight object. Call with null for reset. @@ -11467,7 +11497,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener changed = true; } - if (requestRectWithoutFocus && isFocused()) { + if (requestRectWithoutFocus || isFocused()) { // This offsets because getInterestingRect() is in terms of viewport coordinates, but // requestRectangleOnScreen() is in terms of content coordinates. diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index fceee4e01799..54d19eb79305 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -206,21 +206,23 @@ public class Toast { String pkg = mContext.getOpPackageName(); TN tn = mTN; tn.mNextView = mNextView; + final boolean isUiContext = mContext.isUiContext(); final int displayId = mContext.getDisplayId(); try { if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { if (mNextView != null) { // It's a custom toast - service.enqueueToast(pkg, mToken, tn, mDuration, displayId); + service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); } else { // It's a text toast ITransientNotificationCallback callback = new CallbackBinder(mCallbacks, mHandler); - service.enqueueTextToast(pkg, mToken, mText, mDuration, displayId, callback); + service.enqueueTextToast(pkg, mToken, mText, mDuration, isUiContext, displayId, + callback); } } else { - service.enqueueToast(pkg, mToken, tn, mDuration, displayId); + service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); } } catch (RemoteException e) { // Empty diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java index 514059456279..e0ee68337061 100644 --- a/core/java/android/window/BackNavigationInfo.java +++ b/core/java/android/window/BackNavigationInfo.java @@ -16,6 +16,8 @@ package android.window; +import android.annotation.AnimRes; +import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -245,6 +247,9 @@ public final class BackNavigationInfo implements Parcelable { public static final class CustomAnimationInfo implements Parcelable { private final String mPackageName; private int mWindowAnimations; + @AnimRes private int mCustomExitAnim; + @AnimRes private int mCustomEnterAnim; + @ColorInt private int mCustomBackground; /** * The package name of the windowAnimations. @@ -261,6 +266,27 @@ public final class BackNavigationInfo implements Parcelable { return mWindowAnimations; } + /** + * The exit animation resource Id of customize activity transition. + */ + public int getCustomExitAnim() { + return mCustomExitAnim; + } + + /** + * The entering animation resource Id of customize activity transition. + */ + public int getCustomEnterAnim() { + return mCustomEnterAnim; + } + + /** + * The background color of customize activity transition. + */ + public int getCustomBackground() { + return mCustomBackground; + } + public CustomAnimationInfo(@NonNull String packageName) { this.mPackageName = packageName; } @@ -274,11 +300,17 @@ public final class BackNavigationInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mPackageName); dest.writeInt(mWindowAnimations); + dest.writeInt(mCustomEnterAnim); + dest.writeInt(mCustomExitAnim); + dest.writeInt(mCustomBackground); } private CustomAnimationInfo(@NonNull Parcel in) { mPackageName = in.readString8(); mWindowAnimations = in.readInt(); + mCustomEnterAnim = in.readInt(); + mCustomExitAnim = in.readInt(); + mCustomBackground = in.readInt(); } @Override @@ -349,10 +381,25 @@ public final class BackNavigationInfo implements Parcelable { * Set windowAnimations for customize animation. */ public Builder setWindowAnimations(String packageName, int windowAnimations) { - mCustomAnimationInfo = new CustomAnimationInfo(packageName); + if (mCustomAnimationInfo == null) { + mCustomAnimationInfo = new CustomAnimationInfo(packageName); + } mCustomAnimationInfo.mWindowAnimations = windowAnimations; return this; } + /** + * Set resources ids for customize activity animation. + */ + public Builder setCustomAnimation(String packageName, @AnimRes int enterResId, + @AnimRes int exitResId, @ColorInt int backgroundColor) { + if (mCustomAnimationInfo == null) { + mCustomAnimationInfo = new CustomAnimationInfo(packageName); + } + mCustomAnimationInfo.mCustomExitAnim = exitResId; + mCustomAnimationInfo.mCustomEnterAnim = enterResId; + mCustomAnimationInfo.mCustomBackground = backgroundColor; + return this; + } /** * Builds and returns an instance of {@link BackNavigationInfo} diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index b83d1d83f036..f19f6c7949d2 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -87,6 +87,8 @@ public class AccessibilityShortcutController { new ComponentName("com.android.server.accessibility", "OneHandedMode"); public static final ComponentName REDUCE_BRIGHT_COLORS_COMPONENT_NAME = new ComponentName("com.android.server.accessibility", "ReduceBrightColors"); + public static final ComponentName FONT_SIZE_COMPONENT_NAME = + new ComponentName("com.android.server.accessibility", "FontSize"); // The component name for the sub setting of Accessibility button in Accessibility settings public static final ComponentName ACCESSIBILITY_BUTTON_COMPONENT_NAME = diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java index bcbfdc96a18f..d07058daad8a 100644 --- a/core/java/com/android/internal/app/LocaleStore.java +++ b/core/java/com/android/internal/app/LocaleStore.java @@ -657,6 +657,7 @@ public class LocaleStore { // of supported locales. result.mIsPseudo = localeInfo.mIsPseudo; result.mIsTranslated = localeInfo.mIsTranslated; + result.mHasNumberingSystems = localeInfo.mHasNumberingSystems; result.mSuggestionFlags = localeInfo.mSuggestionFlags; return result; } diff --git a/core/java/com/android/internal/expresslog/Histogram.java b/core/java/com/android/internal/expresslog/Histogram.java index 65fbb03bf967..2fe784a5a855 100644 --- a/core/java/com/android/internal/expresslog/Histogram.java +++ b/core/java/com/android/internal/expresslog/Histogram.java @@ -54,6 +54,19 @@ public final class Histogram { /*count*/ 1, binIndex); } + /** + * Logs increment sample count for automatically calculated bin + * + * @param uid used as a dimension for the count metric + * @param sample value + * @hide + */ + public void logSampleWithUid(int uid, float sample) { + final int binIndex = mBinOptions.getBinForSample(sample); + FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_UID_HISTOGRAM_SAMPLE_REPORTED, + mMetricIdHash, /*count*/ 1, binIndex, uid); + } + /** Used by Histogram to map data sample to corresponding bin */ public interface BinOptions { /** diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java index 3226669ee750..1c0da1846536 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -328,6 +328,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener mTracingStarted = true; markEvent("FT#begin"); Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId); + markEvent("FT#layerId#" + mSurfaceControl.getLayerId()); mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl); if (!mSurfaceOnly) { mRendererWrapper.addObserver(mObserver); @@ -437,8 +438,10 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener "The length of the trace event description <%s> exceeds %d", desc, MAX_LENGTH_EVENT_DESC)); } - Trace.beginSection(TextUtils.formatSimple("%s#%s", mSession.getName(), desc)); - Trace.endSection(); + if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) { + Trace.instant(Trace.TRACE_TAG_APP, + TextUtils.formatSimple("%s#%s", mSession.getName(), desc)); + } } private void notifyCujEvent(String action) { diff --git a/core/java/com/android/internal/os/TimeoutRecord.java b/core/java/com/android/internal/os/TimeoutRecord.java index 2f6091bc3266..a0e29347d07f 100644 --- a/core/java/com/android/internal/os/TimeoutRecord.java +++ b/core/java/com/android/internal/os/TimeoutRecord.java @@ -18,6 +18,8 @@ package com.android.internal.os; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; import android.content.Intent; import android.os.SystemClock; @@ -98,18 +100,41 @@ public class TimeoutRecord { /** Record for a broadcast receiver timeout. */ @NonNull + public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent, + @Nullable String packageName, @Nullable String className) { + final Intent logIntent; + if (packageName != null) { + if (className != null) { + logIntent = new Intent(intent); + logIntent.setComponent(new ComponentName(packageName, className)); + } else { + logIntent = new Intent(intent); + logIntent.setPackage(packageName); + } + } else { + logIntent = intent; + } + return forBroadcastReceiver(logIntent); + } + + /** Record for a broadcast receiver timeout. */ + @NonNull public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent) { - String reason = "Broadcast of " + intent.toString(); - return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason); + final StringBuilder reason = new StringBuilder("Broadcast of "); + intent.toString(reason); + return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason.toString()); } /** Record for a broadcast receiver timeout. */ @NonNull public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent, long timeoutDurationMs) { - String reason = "Broadcast of " + intent.toString() + ", waited " + timeoutDurationMs - + "ms"; - return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason); + final StringBuilder reason = new StringBuilder("Broadcast of "); + intent.toString(reason); + reason.append(", waited "); + reason.append(timeoutDurationMs); + reason.append("ms"); + return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason.toString()); } /** Record for an input dispatch no focused window timeout */ diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 85cb15bdd906..a95ce64ecec8 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -51,6 +51,7 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.TimingsTraceLog; +import android.view.WindowManager; import android.webkit.WebViewFactory; import android.widget.TextView; @@ -72,6 +73,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.security.Provider; import java.security.Security; +import java.util.ArrayList; +import java.util.List; /** * Startup class for the zygote process. @@ -384,33 +387,49 @@ public class ZygoteInit { * classpath. */ private static void cacheNonBootClasspathClassLoaders() { + // Ordered dependencies first + final List<SharedLibraryInfo> libs = new ArrayList<>(); // These libraries used to be part of the bootclasspath, but had to be removed. // Old system applications still get them for backwards compatibility reasons, // so they are cached here in order to preserve performance characteristics. - SharedLibraryInfo hidlBase = new SharedLibraryInfo( + libs.add(new SharedLibraryInfo( "/system/framework/android.hidl.base-V1.0-java.jar", null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/, - false /*isNative*/); - SharedLibraryInfo hidlManager = new SharedLibraryInfo( + false /*isNative*/)); + libs.add(new SharedLibraryInfo( "/system/framework/android.hidl.manager-V1.0-java.jar", null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/, - false /*isNative*/); + false /*isNative*/)); - SharedLibraryInfo androidTestBase = new SharedLibraryInfo( + libs.add(new SharedLibraryInfo( "/system/framework/android.test.base.jar", null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/, - false /*isNative*/); - - ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders( - new SharedLibraryInfo[]{ - // ordered dependencies first - hidlBase, - hidlManager, - androidTestBase, - }); + false /*isNative*/)); + + // WindowManager Extensions is an optional shared library that is required for WindowManager + // Jetpack to fully function. Since it is a widely used library, preload it to improve apps + // startup performance. + if (WindowManager.hasWindowExtensionsEnabled()) { + final String systemExtFrameworkPath = + new File(Environment.getSystemExtDirectory(), "framework").getPath(); + libs.add(new SharedLibraryInfo( + systemExtFrameworkPath + "/androidx.window.extensions.jar", + "androidx.window.extensions", null /*codePaths*/, + "androidx.window.extensions", SharedLibraryInfo.VERSION_UNDEFINED, + SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, + null /*dependentPackages*/, null /*dependencies*/, false /*isNative*/)); + libs.add(new SharedLibraryInfo( + systemExtFrameworkPath + "/androidx.window.sidecar.jar", + "androidx.window.sidecar", null /*codePaths*/, + "androidx.window.sidecar", SharedLibraryInfo.VERSION_UNDEFINED, + SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, + null /*dependentPackages*/, null /*dependencies*/, false /*isNative*/)); + } + + ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders(libs); } /** diff --git a/core/java/com/android/internal/os/anr/AnrLatencyTracker.java b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java index 6a6165687981..096d1cd212be 100644 --- a/core/java/com/android/internal/os/anr/AnrLatencyTracker.java +++ b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java @@ -137,14 +137,14 @@ public class AnrLatencyTracker implements AutoCloseable { close(); } - /** Records the start of ActivityManagerService#dumpStackTraces. */ + /** Records the start of StackTracesDumpHelper#dumpStackTraces. */ public void dumpStackTracesStarted() { mDumpStackTracesStartUptime = getUptimeMillis(); Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dumpStackTraces()"); } - /** Records the end of ActivityManagerService#dumpStackTraces. */ + /** Records the end of StackTracesDumpHelper#dumpStackTraces. */ public void dumpStackTracesEnded() { Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -328,7 +328,7 @@ public class AnrLatencyTracker implements AutoCloseable { anrSkipped("appNotResponding"); } - /** Records a skipped ANR in ActivityManagerService#dumpStackTraces. */ + /** Records a skipped ANR in StackTracesDumpHelper#dumpStackTraces. */ public void anrSkippedDumpStackTraces() { anrSkipped("dumpStackTraces"); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 8f04cdaf8fde..c1dbc87a2a10 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -111,6 +111,7 @@ interface IStatusBarService void clickTile(in ComponentName tile); @UnsupportedAppUsage void handleSystemKey(in int key); + int getLastSystemKey(); /** * Methods to show toast messages for screen pinning diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 9a4610e8c0a1..549169388e45 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -150,12 +150,13 @@ interface IInputMethodManager { /** Prepares delegation of starting stylus handwriting session to a different editor **/ void prepareStylusHandwritingDelegation(in IInputMethodClient client, + in int userId, in String delegatePackageName, in String delegatorPackageName); /** Accepts and starts a stylus handwriting session for the delegate view **/ boolean acceptStylusHandwritingDelegation(in IInputMethodClient client, - in String delegatePackageName, in String delegatorPackageName); + in int userId, in String delegatePackageName, in String delegatorPackageName); /** Returns {@code true} if currently selected IME supports Stylus handwriting. */ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java index a0f7905771a2..f08e86082aa9 100644 --- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java +++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java @@ -5,12 +5,14 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; +import android.app.AppGlobals; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.os.Handler; import android.os.Parcelable; import android.os.SystemClock; +import android.text.TextFlags; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -46,8 +48,6 @@ import java.util.List; */ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener { - private static final int ITEM_LAYOUT = com.android.internal.R.layout.cascading_menu_item_layout; - @Retention(RetentionPolicy.SOURCE) @IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT}) public @interface HorizPosition {} @@ -190,6 +190,7 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey private Callback mPresenterCallback; private ViewTreeObserver mTreeObserver; private PopupWindow.OnDismissListener mOnDismissListener; + private final int mItemLayout; /** Whether popup menus should disable exit animations when closing. */ private boolean mShouldCloseImmediately; @@ -215,6 +216,12 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth)); mSubMenuHoverHandler = new Handler(); + + mItemLayout = AppGlobals.getIntCoreSetting( + TextFlags.KEY_ENABLE_NEW_CONTEXT_MENU, + TextFlags.ENABLE_NEW_CONTEXT_MENU_DEFAULT ? 1 : 0) != 0 + ? com.android.internal.R.layout.cascading_menu_item_layout_material + : com.android.internal.R.layout.cascading_menu_item_layout; } @Override @@ -348,7 +355,7 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey */ private void showMenu(@NonNull MenuBuilder menu) { final LayoutInflater inflater = LayoutInflater.from(mContext); - final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly, ITEM_LAYOUT); + final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly, mItemLayout); // Apply "force show icon" setting. There are 3 cases: // (1) This is the top level menu and icon spacing is forced. Add spacing. diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java index 0d2b29b69586..cb1abf13c109 100644 --- a/core/java/com/android/internal/view/menu/ListMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java @@ -16,12 +16,12 @@ package com.android.internal.view.menu; -import com.android.internal.R; - +import android.app.AppGlobals; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.TextFlags; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -61,6 +61,8 @@ public class ListMenuItemView extends LinearLayout private int mMenuType; + private boolean mUseNewContextMenu; + private LayoutInflater mInflater; private boolean mForceShowIcon; @@ -87,6 +89,10 @@ public class ListMenuItemView extends LinearLayout a.recycle(); b.recycle(); + + mUseNewContextMenu = AppGlobals.getIntCoreSetting( + TextFlags.KEY_ENABLE_NEW_CONTEXT_MENU, + TextFlags.ENABLE_NEW_CONTEXT_MENU_DEFAULT ? 1 : 0) != 0; } public ListMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) { @@ -283,7 +289,9 @@ public class ListMenuItemView extends LinearLayout private void insertIconView() { LayoutInflater inflater = getInflater(); - mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon, + mIconView = (ImageView) inflater.inflate( + mUseNewContextMenu ? com.android.internal.R.layout.list_menu_item_fixed_size_icon : + com.android.internal.R.layout.list_menu_item_icon, this, false); addContentView(mIconView, 0); } diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index a8abe50a9755..2a670e865ced 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -556,7 +556,8 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jin // connect to camera service static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jint cameraId, jstring clientPackageName, - jboolean overrideToPortrait) { + jboolean overrideToPortrait, + jboolean forceSlowJpegMode) { // Convert jstring to String16 const char16_t *rawClientName = reinterpret_cast<const char16_t*>( env->GetStringChars(clientPackageName, NULL)); @@ -568,7 +569,7 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj int targetSdkVersion = android_get_application_target_sdk_version(); sp<Camera> camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID, - targetSdkVersion, overrideToPortrait); + targetSdkVersion, overrideToPortrait, forceSlowJpegMode); if (camera == NULL) { return -EACCES; } @@ -1054,7 +1055,7 @@ static const JNINativeMethod camMethods[] = { {"getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras}, {"_getCameraInfo", "(IZLandroid/hardware/Camera$CameraInfo;)V", (void *)android_hardware_Camera_getCameraInfo}, - {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;Z)I", + {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;ZZ)I", (void *)android_hardware_Camera_native_setup}, {"native_release", "()V", (void *)android_hardware_Camera_release}, {"setPreviewSurface", "(Landroid/view/Surface;)V", diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index a7c7d0ba35bc..b24dc8a9e63b 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -413,9 +413,13 @@ protected: if (env->ExceptionCheck()) { ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred()); - binder_report_exception(env, excep.get(), - "*** Uncaught remote exception! " - "(Exceptions are not yet supported across processes.)"); + + auto state = IPCThreadState::self(); + String8 msg; + msg.appendFormat("*** Uncaught remote exception! Exceptions are not yet supported " + "across processes. Client PID %d UID %d.", + state->getCallingPid(), state->getCallingUid()); + binder_report_exception(env, excep.get(), msg.c_str()); res = JNI_FALSE; } @@ -431,6 +435,7 @@ protected: ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred()); binder_report_exception(env, excep.get(), "*** Uncaught exception in onBinderStrictModePolicyChange"); + // TODO: should turn this to fatal? } // Need to always call through the native implementation of diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 0c3ff6c28ea7..410b44161cf6 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -18,19 +18,17 @@ //#define LOG_NDEBUG 0 -#include <nativehelper/JNIHelp.h> - -#include <inttypes.h> - #include <android_runtime/AndroidRuntime.h> +#include <android_runtime/Log.h> #include <gui/DisplayEventDispatcher.h> +#include <inttypes.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedLocalRef.h> #include <utils/Log.h> #include <utils/Looper.h> #include <utils/threads.h> -#include "android_os_MessageQueue.h" - -#include <nativehelper/ScopedLocalRef.h> +#include "android_os_MessageQueue.h" #include "core_jni_helpers.h" namespace android { @@ -133,6 +131,12 @@ static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventDa gDisplayEventReceiverClassInfo .frameTimelineClassInfo.clazz, /*initial element*/ NULL)); + if (!frameTimelineObjs.get() || env->ExceptionCheck()) { + ALOGW("%s: Failed to create FrameTimeline array", __func__); + LOGW_EX(env); + env->ExceptionClear(); + return NULL; + } for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i]; ScopedLocalRef<jobject> @@ -144,6 +148,12 @@ static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventDa frameTimeline.vsyncId, frameTimeline.expectedPresentationTime, frameTimeline.deadlineTimestamp)); + if (!frameTimelineObj.get() || env->ExceptionCheck()) { + ALOGW("%s: Failed to create FrameTimeline object", __func__); + LOGW_EX(env); + env->ExceptionClear(); + return NULL; + } env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get()); } return env->NewObject(gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 49f47c56e6a6..2e9f1790a4a5 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -316,8 +316,9 @@ static void pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj, outPointerProperties->clear(); outPointerProperties->id = env->GetIntField(pointerPropertiesObj, gPointerPropertiesClassInfo.id); - outPointerProperties->toolType = env->GetIntField(pointerPropertiesObj, + const int32_t toolType = env->GetIntField(pointerPropertiesObj, gPointerPropertiesClassInfo.toolType); + outPointerProperties->toolType = static_cast<ToolType>(toolType); } static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* pointerProperties, @@ -325,7 +326,7 @@ static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* po env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.id, pointerProperties->id); env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.toolType, - pointerProperties->toolType); + static_cast<int32_t>(pointerProperties->toolType)); } @@ -535,7 +536,7 @@ static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz if (!validatePointerIndex(env, pointerIndex, *event)) { return -1; } - return event->getToolType(pointerIndex); + return static_cast<jint>(event->getToolType(pointerIndex)); } static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz, diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 82e1777ab7cb..e6c8557a8c50 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -389,6 +389,8 @@ message ActivityRecordProto { optional bool provides_max_bounds = 34; optional bool enable_recents_screenshot = 35; optional int32 last_drop_input_mode = 36; + optional int32 override_orientation = 37 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"]; + optional bool should_send_compat_fake_focus = 38; } /* represents WindowToken */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 12106c7a480e..78d39236b392 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1374,8 +1374,7 @@ android:permissionFlags="hardRestricted" android:protectionLevel="dangerous" /> - <!-- Allows an application to write (but not read) the user's - call log data. + <!-- Allows an application to write and read the user's call log data. <p class="note"><strong>Note:</strong> If your app uses the {@link #WRITE_CONTACTS} permission and <em>both</em> your <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code @@ -1747,9 +1746,11 @@ android:protectionLevel="dangerous" android:permissionFlags="hardRestricted" /> - <!-- Allows an application to access wrist temperature data from the watch sensors. + <!-- @TestApi Allows an application to access wrist temperature data from the watch sensors. <p class="note"><strong>Note: </strong> This permission is for Wear OS only. - <p>Protection level: dangerous --> + <p>Protection level: dangerous + @hide + --> <permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE" android:permissionGroup="android.permission-group.UNDEFINED" android:label="@string/permlab_bodySensorsWristTemperature" @@ -1757,7 +1758,7 @@ android:backgroundPermission="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND" android:protectionLevel="dangerous" /> - <!-- Allows an application to access wrist temperature data from the watch sensors. + <!-- @TestApi Allows an application to access wrist temperature data from the watch sensors. If you're requesting this permission, you must also request {@link #BODY_SENSORS_WRIST_TEMPERATURE}. Requesting this permission by itself doesn't give you wrist temperature body sensors access. @@ -1767,6 +1768,7 @@ <p> This is a hard restricted permission which cannot be held by an app until the installer on record allowlists the permission. For more details see {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}. + @hide --> <permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND" android:permissionGroup="android.permission-group.UNDEFINED" @@ -4206,14 +4208,14 @@ <permission android:name="android.permission.WRITE_DEVICE_CONFIG" android:protectionLevel="signature|verifier|configurator"/> - <!-- @SystemApi @TestApi @hide Allows an application to read/write sync disabled mode config. + <!-- @SystemApi @TestApi @hide Allows an application to modify only allowlisted settings. <p>Not for use by third-party applications. --> - <permission android:name="android.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG" + <permission android:name="android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG" android:protectionLevel="signature|verifier|configurator"/> - <!-- @SystemApi @TestApi @hide Allows an application to modify only allowlisted settings. + <!-- @SystemApi @TestApi @hide Allows an application to read/write sync disabled mode config. <p>Not for use by third-party applications. --> - <permission android:name="android.permission.ALLOWLISTED_WRITE_DEVICE_CONFIG" + <permission android:name="android.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG" android:protectionLevel="signature|verifier|configurator"/> <!-- @SystemApi @hide Allows an application to read config settings. @@ -7401,6 +7403,8 @@ <p>Protection level: normal --> <permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" + android:label="@string/permlab_updatePackagesWithoutUserAction" + android:description="@string/permdesc_updatePackagesWithoutUserAction" android:protectionLevel="normal" /> <uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"/> diff --git a/core/res/res/layout/cascading_menu_item_layout_material.xml b/core/res/res/layout/cascading_menu_item_layout_material.xml new file mode 100644 index 000000000000..168ed78d66ca --- /dev/null +++ b/core/res/res/layout/cascading_menu_item_layout_material.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Keep in sync with popup_menu_item_layout.xml (which only differs in the title and shortcut + position). --> +<com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minWidth="112dip" + android:maxWidth="280dip" + android:orientation="vertical" > + + <ImageView + android:id="@+id/group_divider" + android:layout_width="match_parent" + android:layout_height="1dip" + android:layout_marginTop="8dip" + android:layout_marginBottom="8dip" + android:background="@drawable/list_divider_material" /> + + <LinearLayout + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="48dip" + android:layout_marginStart="12dip" + android:layout_marginEnd="12dip" + android:duplicateParentState="true" > + + <!-- Icon will be inserted here. --> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="6dip" + android:textAppearance="?attr/textAppearanceLargePopupMenu" + android:singleLine="true" + android:duplicateParentState="true" + android:textAlignment="viewStart" /> + + <Space + android:layout_width="0dip" + android:layout_height="1dip" + android:layout_weight="1"/> + + <TextView + android:id="@+id/shortcut" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="16dip" + android:textAppearance="?attr/textAppearanceSmallPopupMenu" + android:singleLine="true" + android:duplicateParentState="true" + android:textAlignment="viewEnd" /> + + <ImageView + android:id="@+id/submenuarrow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginStart="8dp" + android:scaleType="center" + android:visibility="gone" /> + + <!-- Checkbox, and/or radio button will be inserted here. --> + + </LinearLayout> + +</com.android.internal.view.menu.ListMenuItemView> diff --git a/core/res/res/layout/list_menu_item_fixed_size_icon.xml b/core/res/res/layout/list_menu_item_fixed_size_icon.xml new file mode 100644 index 000000000000..7797682d1967 --- /dev/null +++ b/core/res/res/layout/list_menu_item_fixed_size_icon.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ImageView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_gravity="center_vertical" + android:layout_marginStart="0dip" + android:layout_marginEnd="6dip" + android:layout_marginTop="0dip" + android:layout_marginBottom="0dip" + android:scaleType="centerInside" + android:duplicateParentState="true" /> + diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 42e5188ac516..a1c2a5ac9031 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Laat die houer toe om die kenmerke-inligting vir \'n program te begin bekyk."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"kry toegang tot sensordata teen \'n hoë monsternemingkoers"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Laat die program toe om monsters van sensordata teen \'n hoër koers as 200 Hz te neem"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Stel wagwoordreëls"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Beheer die lengte en die karakters wat in skermslotwagwoorde en -PIN\'e toegelaat word."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitor pogings om skerm te ontsluit"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 26f99bfe5ee0..6a32577ada3f 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -140,8 +140,7 @@ <string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string> <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"የWi-Fi ጥሪ"</string> <string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string> - <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) --> - <skip /> + <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"የWi-Fi ጥሪ"</string> <string name="wifi_calling_off_summary" msgid="5626710010766902560">"ጠፍቷል"</string> <string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"በ Wi-Fi በኩል ደውል"</string> <string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ከተንቀሳቃሽ ስልክ አውታረ መረብ በኩል ደውል"</string> @@ -801,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ያዢው የአንድ መተግበሪያ የባህሪያት መረጃን ማየት እንዲጀምር ያስችለዋል።"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"የዳሳሽ ውሂቡን በከፍተኛ የናሙና ብዛት ላይ ይድረሱበት"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"መተግበሪያው የዳሳሽ ውሂቡን ከ200 ኸ በሚበልጥ ፍጥነት ናሙና እንዲያደርግ ይፈቅድለታል"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"የይለፍ ቃል ደንቦች አዘጋጅ"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"በማያ ገጽ መቆለፊያ የይለፍ ቃሎች እና ፒኖች ውስጥ የሚፈቀዱ ቁምፊዎችን እና ርዝመታቸውን ተቆጣጠር።"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"የማሳያ-ክፈት ሙከራዎችን ክትትል ያድርጉባቸው"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 7335043de246..98c2e0d651c6 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -804,6 +804,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"للسماح للمالك ببدء عرض معلومات عن ميزات التطبيق."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"الوصول إلى بيانات جهاز الاستشعار بمعدّل مرتفع للبيانات في الملف الصوتي"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"يسمح هذا الأذن للتطبيق بزيادة بيانات جهاز الاستشعار بمعدّل بيانات في الملف الصوتي أكبر من 200 هرتز."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"تعيين قواعد كلمة المرور"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"للتحكم في الطول والأحرف المسموح بها في كلمات المرور وأرقام التعريف الشخصي في قفل الشاشة."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"مراقبة محاولات فتح قفل الشاشة"</string> @@ -2328,12 +2332,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"يستخدم \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" كلتا الشاشتين لعرض المحتوى."</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"الجهاز ساخن للغاية"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ميزة \"استخدام الشاشتين\" غير متاحة لأن هاتفك ساخن للغاية."</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ميزة Dual Screen غير متاحة"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ميزة Dual Screen غير متاحة لأن ميزة \"توفير شحن البطارية\" مفعّلة. ويمكنك إيقاف هذا الإجراء من خلال \"الإعدادات\"."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"الانتقال إلى الإعدادات"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"إيقاف"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"تم ضبط \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\""</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"تم ضبط تنسيق لوحة المفاتيح على <xliff:g id="LAYOUT_1">%s</xliff:g>. انقر لتغيير الإعدادات."</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 9be6860d54a3..7a265aad1c59 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ধাৰকক কোনো এপৰ সুবিধাসমূহৰ সম্পর্কীয় তথ্য চোৱাটো আৰম্ভ কৰিবলৈ দিয়ে।"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"এটা উচ্চ ছেম্পলিঙৰ হাৰত ছেন্সৰৰ ডেটা এক্সেছ কৰে"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"এপ্টোক ২০০ হাৰ্টজতকৈ অধিক হাৰত ছেন্সৰৰ ডেটাৰ নমুনা ল’বলৈ অনুমতি দিয়ে"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"পাছৱর্ডৰ নিয়ম ছেট কৰক"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"স্ক্ৰীন লক পাছৱৰ্ড আৰু পিনত অনুমোদিত দৈৰ্ঘ্য আৰু বৰ্ণবোৰ নিয়ন্ত্ৰণ কৰক।।"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"স্ক্ৰীন আনলক কৰা প্ৰয়াসবোৰ নিৰীক্ষণ কৰক"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 94ceba514ff7..a26fe9c42aa7 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"İstifadəçinin tətbiqin funksiyaları barədə məlumatları görməyə başlamasına icazə verir."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"sensor datasına yüksək ölçmə sürəti ilə giriş etmək"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Tətbiqə sensor datasını 200 Hz-dən yüksək sürətlə ölçməyə imkan verir"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Parol qaydalarını təyin edin"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Ekran kilidinin parolu və PINlərində icazə verilən uzunluq və simvollara nəzarət edin."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Ekranı kiliddən çıxarmaq üçün edilən cəhdlərə nəzarət edin"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index fa6991f88c79..76f136de3524 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Dozvoljava nosiocu dozvole da započne pregledanje informacija o funkcijama aplikacije."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora pri velikoj brzini uzorkovanja"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Dozvoljava aplikaciji da uzima uzorak podataka senzora pri brzini većoj od 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Podešavanje pravila za lozinku"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontroliše dužinu i znakove dozvoljene u lozinkama i PIN-ovima za zaključavanje ekrana."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Nadgledajte pokušaje otključavanja ekrana"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 3037acba8144..8938da77953a 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Дазваляе трымальніку запусціць прагляд інфармацыі пра функцыі для праграмы."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"атрымліваць даныя датчыка з высокай частатой дыскрэтызацыі"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Праграма зможа распазнаваць даныя датчыка з частатой звыш 200 Гц"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Устанавіць правілы паролю"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Кіраваць даўжынёй і сімваламі, дазволенымі пры ўводзе пароляў і PIN-кодаў блакіроўкі экрана."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Сачыць за спробамі разблакіроўкі экрана"</string> @@ -2326,12 +2330,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" выкарыстоўвае абодва экраны для паказу змесціва"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Прылада моцна нагрэлася"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Функцыя \"Двайны экран\" недаступная, бо тэлефон моцна награваецца"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функцыя Dual Screen недаступная"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функцыя Dual Screen недаступная, бо ўключаны рэжым энергазберажэння. Вы можаце выключыць яго ў Наладах."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Перайсці ў Налады."</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Выключыць"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Прылада \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\" наладжана"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Раскладка клавіятуры наладжана для мовы \"<xliff:g id="LAYOUT_1">%s</xliff:g>\". Націсніце, каб змяніць."</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index a70d59f40a0e..f2fddeea6f5d 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Разрешава на притежателя да стартира прегледа на информацията за функциите на дадено приложение."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"осъществяване на достъп до данните от сензорите при висока скорост на семплиране"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Разрешава на приложението да семплира данните от сензорите със скорост, по-висока от 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Задаване на правила за паролата"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Контролира дължината и разрешените знаци за паролите и ПИН кодовете за заключване на екрана."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Наблюдаване на опитите за отключване на екрана"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 16cbc773148a..2856cf3f9ffb 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"কোনও অ্যাপের ফিচার সম্পর্কিত তথ্য দেখা শুরু করতে অনুমতি দেয়।"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"হাই স্যাম্পলিং রেটে সেন্সর ডেটা অ্যাক্সেস করুন"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz-এর বেশি রেটে অ্যাপকে স্যাম্পল সেন্সর ডেটার জন্য অনুমতি দিন"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"পাসওয়ার্ড নিয়মগুলি সেট করে"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"স্ক্রিন লক করার পাসওয়ার্ডগুলিতে অনুমতিপ্রাপ্ত অক্ষর এবং দৈর্ঘ্য নিয়ন্ত্রণ করে৷"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"স্ক্রিন আনলক করার প্রচেষ্টাগুলির উপরে নজর রাখুন"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 0b78d26c71a8..2fb1029bd502 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Dozvoljava vlasniku da pokrene pregled informacija o funkcijama za aplikaciju."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora velikom brzinom uzorkovanja"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Dozvoljava aplikaciji da uzorkuje podatke senzora brzinom većom od 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Postavljanje pravila za lozinke"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrolira dužinu i znakove koji su dozvoljeni u lozinkama za zaključavanje ekrana i PIN-ovima."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Prati pokušaje otključavanja ekrana"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index f08cb3a6f156..43542b89ca85 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet que el propietari vegi la informació de les funcions d\'una aplicació."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"accedir a les dades del sensor a una freqüència de mostratge alta"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permet que l\'aplicació dugui a terme un mostratge de les dades del sensor a una freqüència superior a 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Definir les normes de contrasenya"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Permet controlar la longitud i el nombre de caràcters permesos a les contrasenyes i als PIN del bloqueig de pantalla."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Supervisar els intents de desbloqueig de la pantalla"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index d62434553307..a3ea1bba78b7 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Umožňuje držiteli zobrazit informace o funkcích aplikace."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"přístup k datům ze senzorů s vyšší vzorkovací frekvencí"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Umožňuje aplikaci vzorkovat data ze senzorů s frekvencí vyšší než 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Nastavit pravidla pro heslo"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Ovládání délky a znaků povolených v heslech a kódech PIN zámku obrazovky."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Sledovat pokusy o odemknutí obrazovky"</string> @@ -2326,12 +2330,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> používá k zobrazení obsahu oba displeje"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Zařízení je příliš horké"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dvojitá obrazovka není k dispozici, protože se telefon příliš zahřívá"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Funkce Dual Screen není k dispozici"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Funkce Dual Screen není k dispozici, protože je zapnutý spořič baterie. Tuto možnost můžete vypnout v nastavení."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Přejít do Nastavení"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Vypnout"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Zařízení <xliff:g id="DEVICE_NAME">%s</xliff:g> je nakonfigurováno"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Rozložení klávesnice je nastaveno na <xliff:g id="LAYOUT_1">%s</xliff:g>. Klepnutím jej změníte."</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 46269af8a734..1cf8097b744a 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Giver den app, som har tilladelsen, mulighed for at se oplysninger om en apps funktioner."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"få adgang til sensordata ved høj samplingfrekvens"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Tillader, at appen kan sample sensordata ved en højere frekvens end 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Angiv regler for adgangskoder"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Tjek længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Overvåg forsøg på oplåsning af skærm"</string> @@ -1912,7 +1916,7 @@ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishingadvarsel"</string> <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbejdsprofil"</string> <string name="notification_alerted_content_description" msgid="6139691253611265992">"Underrettet"</string> - <string name="notification_verified_content_description" msgid="6401483602782359391">"Bekræftet"</string> + <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificeret"</string> <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Udvid"</string> <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Skjul"</string> <string name="expand_action_accessibility" msgid="1947657036871746627">"Slå udvidelse til eller fra"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger begge skærme til at vise indhold"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Enheden er for varm"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dobbeltskærm er ikke tilgængelig, fordi din telefon er for varm"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen er ikke tilgængelig"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen er ikke tilgængelig, fordi Batterisparefunktion er aktiveret. Du kan deaktivere dette i Indstillinger."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Gå til Indstillinger"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Deaktiver"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> er konfigureret"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Tastaturlayoutet er angivet som <xliff:g id="LAYOUT_1">%s</xliff:g>. Tryk for at ændre dette."</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index afb2c73b09d5..bd18f4e93dac 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Ermöglicht der App, die Informationen über die Funktionen einer anderen App anzusehen."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Sensordaten mit hoher Frequenz auslesen"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Erlaubt der App, Sensordaten mit einer Frequenz von mehr als 200 Hz auszulesen"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Passwortregeln festlegen"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Zulässige Länge und Zeichen für Passwörter für die Displaysperre festlegen"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Versuche zum Entsperren des Displays überwachen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index fd20378ab2aa..1e4629be8c55 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Επιτρέπει στον κάτοχο να ξεκινήσει την προβολή των πληροφοριών για τις λειτουργίες μιας εφαρμογής."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"πρόσβαση σε δεδομένα αισθητήρα με υψηλό ρυθμό δειγματοληψίας"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Επιτρέπει στην εφαρμογή τη δειγματοληψία των δεδομένων αισθητήρα με ρυθμό μεγαλύτερο από 200 Hz."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Ορισμός κανόνων κωδικού πρόσβασης"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Ελέγξτε την έκταση και τους επιτρεπόμενους χαρακτήρες σε κωδικούς πρόσβασης κλειδώματος οθόνης και PIN."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 3cee375c5cbb..2d5f15ae84fe 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Allows the holder to start viewing the features info for an app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"access sensor data at a high sampling rate"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Allows the app to sample sensor data at a rate greater than 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Control the length and the characters allowed in screen lock passwords and PINs."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitor screen unlock attempts"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 311c8a3bbbf8..7d416c68540b 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -800,6 +800,8 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Allows the holder to start viewing the features info for an app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"access sensor data at a high sampling rate"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Allows the app to sample sensor data at a rate greater than 200 Hz"</string> + <string name="permlab_updatePackagesWithoutUserAction" msgid="3363272609642618551">"update app without user action"</string> + <string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Allows the holder to update the app it previously installed without user action"</string> <string name="policylab_limitPassword" msgid="4851829918814422199">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Control the length and the characters allowed in screen lock passwords and PINs."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitor screen unlock attempts"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 9c97a49ef989..3730bd25c074 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Allows the holder to start viewing the features info for an app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"access sensor data at a high sampling rate"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Allows the app to sample sensor data at a rate greater than 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Control the length and the characters allowed in screen lock passwords and PINs."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitor screen unlock attempts"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 86be1a96bbfa..67d124a29f2f 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Allows the holder to start viewing the features info for an app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"access sensor data at a high sampling rate"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Allows the app to sample sensor data at a rate greater than 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Control the length and the characters allowed in screen lock passwords and PINs."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitor screen unlock attempts"</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 44426d708052..310f821fe963 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -800,6 +800,8 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Allows the holder to start viewing the features info for an app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"access sensor data at a high sampling rate"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Allows the app to sample sensor data at a rate greater than 200 Hz"</string> + <string name="permlab_updatePackagesWithoutUserAction" msgid="3363272609642618551">"update app without user action"</string> + <string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Allows the holder to update the app it previously installed without user action"</string> <string name="policylab_limitPassword" msgid="4851829918814422199">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Control the length and the characters allowed in screen lock passwords and PINs."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitor screen unlock attempts"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index d2c12e4f386d..441065371c2e 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que el propietario vea la información de las funciones de una app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Acceder a los datos de sensores a una tasa de muestreo alta"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que la app tome una muestra de los datos de sensores a una tasa superior a 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Establecer reglas de contraseña"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controlar la longitud y los caracteres permitidos en las contraseñas y los PIN para el bloqueo de pantalla."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Supervisa los intentos para desbloquear la pantalla"</string> @@ -2325,12 +2329,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> está usando ambas pantallas para mostrar contenido"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"El dispositivo está muy caliente"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"La Pantalla dual no está disponible porque el teléfono se está calentando demasiado"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen no está disponible"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen no está disponible porque el Ahorro de batería está activado. Puedes desactivar esta opción en la Configuración."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ir a Configuración"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desactivar"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Se configuró <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%s</xliff:g>. Presiona para cambiar esta opción."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 9d06e1511600..3d16439c5300 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que el titular vea la información de las funciones de una aplicación."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"acceder a datos de sensores a una frecuencia de muestreo alta"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que la aplicación consulte datos de sensores a una frecuencia superior a 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Establecimiento de reglas de contraseña"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controla la longitud y los caracteres permitidos en los PIN y en las contraseñas de bloqueo de pantalla."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Supervisar los intentos de desbloqueo de pantalla"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 78f574936a1e..bdf5d52710e3 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Võimaldab omanikul alustada rakenduse funktsioonide teabe vaatamist."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"juurdepääs anduri andmetele kõrgel diskreetimissagedusel"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Võimaldab rakendusel anduri andmeid diskreetida sagedusel, mis on suurem kui 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Parooli reeglite määramine"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Juhitakse ekraaniluku paroolide ja PIN-koodide pikkusi ning lubatud tähemärkide seadeid."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Ekraani avamiskatsete jälgimine"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 53644927cba7..2331536f0e1c 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Aplikazio baten eginbideei buruzko informazioa ikusten hasteko baimena ematen die titularrei."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"atzitu sentsoreen datuen laginak abiadura handian"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Aplikazioak 200 Hz-tik gorako abiaduran hartu ahal izango ditu sentsoreen datuen laginak"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Ezarri pasahitzen arauak"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrolatu pantaila blokeoaren pasahitzen eta PINen luzera eta onartutako karaktereak."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Gainbegiratu pantaila desblokeatzeko saiakerak"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 88dd3a6eebf8..5348e8458163 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"به دارنده اجازه میدهد اطلاعات مربوط به ویژگیهای برنامه را مشاهده کند."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"دسترسی به دادههای حسگر با نرخ نمونهبرداری بالا"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"به برنامه اجازه میدهد دادههای حسگر را با نرخ بیشاز ۲۰۰ هرتز نمونهبرداری کند"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"تنظیم قوانین گذرواژه"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"کنترل طول و نوع نویسههایی که در گذرواژه و پین قفل صفحه مجاز است."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"پایش تلاشهای باز کردن قفل صفحه"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index f007d74ad484..2bc040e8c914 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Antaa luvanhaltijan aloittaa sovelluksen ominaisuustietojen katselun."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"saada pääsyn anturidataan suuremmalla näytteenottotaajuudella"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Sallii sovelluksen ottaa anturidatasta näytteitä yli 200 Hz:n taajuudella"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Asentaa salasanasäännöt"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Hallinnoida ruudun lukituksen salasanoissa ja PIN-koodeissa sallittuja merkkejä ja niiden pituutta."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Tarkkailla näytön avaamisyrityksiä"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> käyttää molempia näyttöjä sisällön näyttämiseen"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Laite on liian lämmin"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Kaksoisnäyttö ei ole käytettävissä, koska puhelin on liian lämmin"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Kaksoisnäyttö ei ole saatavilla"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Kaksoisnäyttö ei ole käytettävissä, koska Virransäästö on päällä. Voit estää tämän asetuksista."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Siirry asetuksiin"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Laita pois päältä"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> määritetty"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Näppäimistöasetteluksi valittu <xliff:g id="LAYOUT_1">%s</xliff:g>. Muuta asetuksia napauttamalla."</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 409f5a2c4ebe..dca160c77280 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet au détenteur de commencer à afficher les renseignements sur les fonctionnalités d\'une application."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"accéder aux données des capteurs à un taux d’échantillonnage élevé"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permet à l’application d’échantillonner les données des capteurs à une fréquence supérieure à 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Définir les règles du mot de passe"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les NIP de verrouillage de l\'écran."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Gérer les tentatives de déverrouillage de l\'écran"</string> @@ -1728,7 +1732,7 @@ <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Pour basculer entre les fonctionnalités, maintenez le doigt sur le bouton d\'accessibilité."</string> <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Pour basculer entre les fonctionnalités, balayez l\'écran vers le haut avec deux doigts et maintenez-les-y."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Pour basculer entre les fonctionnalités, balayez l\'écran vers le haut avec trois doigts et maintenez-les-y."</string> - <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Zoom"</string> + <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Agrandissement"</string> <string name="user_switched" msgid="7249833311585228097">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="user_switching_message" msgid="1912993630661332336">"Passage au profil : <xliff:g id="NAME">%1$s</xliff:g>…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"Déconnexion de <xliff:g id="NAME">%1$s</xliff:g> en cours..."</string> @@ -2325,12 +2329,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise les deux écrans pour afficher le contenu"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"L\'appareil est trop chaud"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Le double écran n\'est pas accessible, car votre téléphone est trop chaud"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"La fonctionnalité Dual Screen n\'est pas accessible"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"La fonctionnalité Dual Screen n\'est pas accessible, car l\'économiseur de pile est activé. Vous pouvez désactiver cette option dans les paramètres."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Accéder aux paramètres"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Désactiver"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> est configuré"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Disposition du clavier définie à <xliff:g id="LAYOUT_1">%s</xliff:g>. Touchez pour modifier."</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 7de81a536505..6092dedd2dc9 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet à l\'appli autorisée de commencer à voir les infos sur les fonctionnalités d\'une appli."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"accéder aux données des capteurs à un taux d\'échantillonnage élevé"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Autorise l\'appli à échantillonner les données des capteurs à un taux supérieur à 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Définir les règles du mot de passe"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les codes d\'accès de verrouillage de l\'écran"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Gérer les tentatives de déverrouillage de l\'écran"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index d748991f41e9..405829de847e 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que o propietario comece a ver a información das funcións dunha aplicación."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"acceder aos datos dos sensores usando unha taxa de mostraxe alta"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que a aplicación recompile mostras dos datos dos sensores cunha taxa superior a 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Establecer as normas de contrasinal"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controla a lonxitude e os caracteres permitidos nos contrasinais e nos PIN de bloqueo da pantalla."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Controlar os intentos de desbloqueo da pantalla"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> está usando ambas as pantallas para mostrar contido"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"O dispositivo está demasiado quente"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"A pantalla dual non está dispoñible porque o teléfono está quentando demasiado"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen non está dispoñible"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen non está dispoñible porque a opción Aforro de batería está activado. Podes desactivar esta función en Configuración."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ir a Configuración"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desactivar"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Configurouse o teclado (<xliff:g id="DEVICE_NAME">%s</xliff:g>)"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"O deseño do teclado estableceuse en <xliff:g id="LAYOUT_1">%s</xliff:g>. Toca para cambialo."</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 53d7fd813545..75099ec56a71 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ધારકને ઍપ માટેની સુવિધાઓની માહિતી જોવાનું શરૂ કરવાની મંજૂરી આપે છે."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ઉચ્ચ સેમ્પ્લિંગ રેટ પર સેન્સરનો ડેટા ઍક્સેસ કરો"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ઍપને 200 Hzથી વધુના દરે સેન્સરના ડેટાના નમૂનાની મંજૂરી આપે છે"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"પાસવર્ડ નિયમો સેટ કરો"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"સ્ક્રીન લૉક પાસવર્ડ અને પિનમાં મંજૂર લંબાઈ અને અક્ષરોને નિયંત્રિત કરો."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"સ્ક્રીનને અનલૉક કરવાના પ્રયત્નોનું નિયમન કરો"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 84f0490cd00a..c56d596a17a3 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -22,7 +22,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="byteShort" msgid="202579285008794431">"B"</string> <string name="fileSizeSuffix" msgid="4233671691980131257">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string> - <string name="untitled" msgid="3381766946944136678">"<शीर्षक-रहित>"</string> + <string name="untitled" msgid="3381766946944136678">"<टाइटल-रहित>"</string> <string name="emptyPhoneNumber" msgid="5812172618020360048">"(कोई फ़ोन नंबर नहीं)"</string> <string name="unknownName" msgid="7078697621109055330">"अज्ञात"</string> <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"वॉइसमेल"</string> @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ऐप्लिकेशन को, किसी ऐप्लिकेशन की सुविधाओं की जानकारी देखने की अनुमति देता है."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"सेंसर डेटा को, नमूने लेने की तेज़ दर पर ऐक्सेस करें"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"यह अनुमति मिलने पर ऐप्लिकेशन, 200 हर्ट्ज़ से ज़्यादा की दर पर सेंसर डेटा का नमूना ले पाएगा"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियम सेट करना"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रीन लॉक पासवर्ड और पिन की लंबाई और उनमें स्वीकृत वर्णों को नियंत्रित करना."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"स्क्रीन अनलॉक करने के की कोशिशों पर नज़र रखना"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index eff55241e17b..4ee5070bca26 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Dopušta nositelju pokretanje prikaza informacija o značajkama aplikacije."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora pri višoj brzini uzorkovanja"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Aplikaciji omogućuje uzorkovanje podataka senzora pri brzini većoj od 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Postavi pravila zaporke"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Upravlja duljinom i znakovima koji su dopušteni u zaporkama i PIN-ovima zaključavanja zaslona."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Nadziri pokušaje otključavanja zaslona"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index e61aba4400d7..757598edc04d 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Engedélyezi az alkalmazás számára, hogy megkezdje az alkalmazások funkcióira vonatkozó adatok megtekintését."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"hozzáférés a szenzoradatokhoz nagy mintavételezési gyakorisággal"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Lehetővé teszi az alkalmazás számára, hogy 200 Hz-nél magasabb gyakorisággal vegyen mintát a szenzoradatokból"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Jelszavakkal kapcsolatos szabályok beállítása"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"A képernyőzár jelszavaiban és PIN kódjaiban engedélyezett karakterek és hosszúság vezérlése."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Képernyőzár-feloldási kísérletek figyelése"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index b1e226e70a04..52ef8842ca52 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Թույլ է տալիս դիտել հավելվածի գործառույթների մասին տեղեկությունները։"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"օգտագործել սենսորների տվյալները բարձր հաճախականության վրա"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Թույլ է տալիս հավելվածին փորձել սենսորների տվյալները 200 Հց-ից բարձր հաճախականության վրա"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Սահմանել գաղտնաբառի կանոնները"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Կառավարել էկրանի ապակողպման գաղտնաբառերի և PIN կոդերի թույլատրելի երկարությունն ու գրանշանները:"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Վերահսկել էկրանի ապակողպման փորձերը"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը երկու էկրաններն էլ օգտագործում է բովանդակություն ցուցադրելու համար"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Սարքը գերտաքացել է"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Կրկնակի էկրանն անհասանելի է, քանի որ ձեր հեռախոսը գերտաքանում է"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen-ը հասանելի չէ"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen-ն անհասանելի է, քանի որ Մարտկոցի տնտեսումը միացված է։ Դուք կարող եք անջատել այս գործառույթը Կարգավորումներում։"</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Անցնել Կարգավորումներ"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Անջատել"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> սարքը կարգավորված է"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Ստեղնաշարի համար կարգավորված է <xliff:g id="LAYOUT_1">%s</xliff:g> դասավորությունը։ Հպեք փոփոխելու համար։"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index ca97e22003c1..8f9199f684ef 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Memungkinkan pemegang mulai melihat info fitur untuk aplikasi."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"mengakses data sensor pada frekuensi sampling yang tinggi"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Mengizinkan aplikasi mengambil sampel data sensor pada frekuensi yang lebih besar dari 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Setel aturan sandi"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Mengontrol panjang dan karakter yang diizinkan dalam sandi dan PIN kunci layar."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Pantau upaya pembukaan kunci layar"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 77ade619be38..330c0d9e8580 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Leyfir handhafa að skoða upplýsingar um eiginleika tiltekins forrits."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"aðgangur að skynjaragögnum með hárri upptökutíðni"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Leyfir forritinu að nota upptökutíðni yfir 200 Hz fyrir skynjaragögn"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Setja reglur um aðgangsorð"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Stjórna lengd og fjölda stafa í aðgangsorðum og PIN-númerum skjáláss."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Fylgjast með tilraunum til að taka skjáinn úr lás"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 8d57810320f4..72b3b0bf96ea 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Consente all\'app che ha questa autorizzazione di iniziare a visualizzare le informazioni relative alle funzionalità di un\'app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Accesso ai dati dei sensori a una frequenza di campionamento elevata"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Consente all\'app di campionare i dati dei sensori a una frequenza maggiore di 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Impostare regole per le password"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controlla la lunghezza e i caratteri ammessi nelle password e nei PIN del blocco schermo."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitorare tentativi di sblocco dello schermo"</string> @@ -1634,7 +1638,7 @@ <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Impostazioni"</string> <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Disconnetti"</string> <string name="media_route_status_scanning" msgid="8045156315309594482">"Ricerca in corso..."</string> - <string name="media_route_status_connecting" msgid="5845597961412010540">"Connessione..."</string> + <string name="media_route_status_connecting" msgid="5845597961412010540">"Connessione in corso..."</string> <string name="media_route_status_available" msgid="1477537663492007608">"Disponibile"</string> <string name="media_route_status_not_available" msgid="480912417977515261">"Non disponibili"</string> <string name="media_route_status_in_use" msgid="6684112905244944724">"In uso"</string> @@ -2325,12 +2329,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> sta usando entrambi i display per mostrare contenuti"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Il dispositivo è troppo caldo"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Il doppio schermo non è disponibile perché il telefono si sta surriscaldando"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen non disponibile"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Il doppio schermo non è disponibile perché il Risparmio energetico è attivato. Puoi disattivare questa opzione in Impostazioni."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Vai a Impostazioni"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Disattiva"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Dispositivo <xliff:g id="DEVICE_NAME">%s</xliff:g> configurato"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Layout tastiera impostato su <xliff:g id="LAYOUT_1">%s</xliff:g>. Tocca per cambiare l\'impostazione."</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 9e283fa55488..bdc482134612 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"בעלי ההרשאה יוכלו להתחיל לצפות בפרטי התכונות של אפליקציות."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"גישה לנתוני חיישנים בתדירות דגימה גבוהה"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"האפליקציה תוכל לדגום נתוני חיישנים בתדירות של מעל 200 הרץ"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"הגדרת כללי סיסמה"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"קביעת האורך הנדרש והתווים המותרים בסיסמאות ובקודי האימות של מסך הנעילה."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"מעקב אחר ניסיונות לביטול של נעילת המסך"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 7d2b2a5179f7..940e12902553 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"アプリの機能情報の表示の開始を所有者に許可します。"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"高サンプリング レートでセンサーデータにアクセスする"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz を超えるレートでセンサーデータをサンプリングすることをアプリに許可します"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"パスワードルールの設定"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"画面ロックのパスワードとPINの長さと使用できる文字を制御します。"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"画面ロック解除試行の監視"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>は 2 画面でコンテンツを表示しています"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"デバイスが熱くなりすぎています"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"スマートフォンが熱くなりすぎているため、デュアル スクリーンを使用できません"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"デュアル スクリーンを使用できません"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"バッテリー セーバーが ON のため、デュアル スクリーンを使用できません。この動作は設定で OFF にできます。"</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"設定に移動"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"オフにする"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g>の設定完了"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"キーボードのレイアウトは<xliff:g id="LAYOUT_1">%s</xliff:g>に設定されています。タップすると変更できます。"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index af735eaf87d2..85050b8e07af 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"მფლობელს საშუალებას აძლევს, დაიწყოს აპის ფუნქციების ინფორმაციის ნახვა."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"სენსორის მონაცემებზე წვდომა სემპლინგის მაღალი სიხშირით"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"საშუალებას აძლევს აპს, მიიღოს სენსორის მონაცემების ნიმუშები 200 ჰც-ზე მეტი სიხშირით"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"პაროლის წესების დაყენება"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"აკონტროლეთ ეკრანის ბლოკირების პაროლებისა და PIN-ების სიმბოლოების სიგრძე."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"ეკრანის განბლოკვის მცდელობების მონიტორინგი"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 5fbe915558f7..0e976c788942 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Қолданбаға функциялар туралы ақпаратты көре бастауды кідіртуге мүмкіндік береді."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"жоғары дискретизация жиілігіндегі датчик деректерін пайдалану"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Қолданбаға жиілігі 200 Гц-тен жоғары датчик деректерінің үлгісін таңдауға рұқсат береді."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Құпия сөз ережелерін тағайындау"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Экран бекітпесінің құпия сөздерінің және PIN кодтарының ұзындығын және оларда рұқсат етілген таңбаларды басқару."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Экран құлпын ашу әркеттерін бақылау"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index f69ff8adf68e..c3fe5b054767 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"អនុញ្ញាតឱ្យកម្មវិធីចាប់ផ្ដើមមើលព័ត៌មានមុខងារសម្រាប់កម្មវិធី។"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ចូលប្រើទិន្នន័យឧបករណ៍ចាប់សញ្ញានៅអត្រាសំណាកខ្ពស់"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"អនុញ្ញាតឱ្យកម្មវិធីធ្វើសំណាកទិន្នន័យឧបករណ៍ចាប់សញ្ញានៅអត្រាលើសពី 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"កំណត់ក្បួនពាក្យសម្ងាត់"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"គ្រប់គ្រងប្រវែង និងតួអក្សរដែលអនុញ្ញាតឲ្យប្រើក្នុងពាក្យសម្ងាត់ និងលេខសម្ងាត់ចាក់សោអេក្រង់។"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"តាមដានការព្យាយាមដោះសោអេក្រង់"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index b503d6bc649f..7ae603f24037 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ಆ್ಯಪ್ನ ವೈಶಿಷ್ಟ್ಯಗಳ ಮಾಹಿತಿಯನ್ನು ವೀಕ್ಷಿಸಲು ಬಳಕೆದಾರರನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ಹೆಚ್ಚಿನ ನಮೂನೆ ದರದಲ್ಲಿ ಸೆನ್ಸಾರ್ ಡೇಟಾ ಪ್ರವೇಶಿಸಿ"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz ಗಿಂತಲೂ ಹೆಚ್ಚಿನ ವೇಗದಲ್ಲಿ ಸೆನ್ಸಾರ್ ಡೇಟಾದ ಮಾದರಿ ಪರೀಕ್ಷಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಿ"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"ಪಾಸ್ವರ್ಡ್ ನಿಮಯಗಳನ್ನು ಹೊಂದಿಸಿ"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"ಪರದೆ ಲಾಕ್ನಲ್ಲಿನ ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಪಿನ್ಗಳ ಅನುಮತಿಸಲಾದ ಅಕ್ಷರಗಳ ಪ್ರಮಾಣವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"ಪರದೆಯ ಅನ್ಲಾಕ್ ಪ್ರಯತ್ನಗಳನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 78dd9ec06e2d..37c8bc7cf6c3 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"권한을 보유한 앱에서 앱의 기능 정보를 보도록 허용합니다."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"더 높은 샘플링 레이트로 센서 데이터 액세스"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"앱에서 200Hz보다 빠른 속도로 센서 데이터를 샘플링하도록 허용합니다."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"비밀번호 규칙 설정"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"화면 잠금 비밀번호와 PIN에 허용되는 길이와 문자 수를 제어합니다."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"화면 잠금 해제 시도 모니터링"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 5e3e3d993c4b..b795fde51e59 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Колдонуучуга функциялары тууралуу маалыматты көрүп баштоо мүмкүнчүлүгүн берет."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"үлгүнү жаздыруу ылдамдыгы жогору болгон сенсор дайындарынын үлгүсүнө мүмкүнчүлүк алуу"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Колдонмолорго сенсор дайындарынын үлгүсү 200 Герцтен жогору болгон үлгүлөрдү алууга уруксат берет"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Сырсөз эрежелерин коюу"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Экран кулпусунун сырсөздөрү менен PIN\'дерине уруксат берилген узундук менен белгилерди көзөмөлдөө."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Экран кулпусун ачуу аракеттерин көзөмөлдөө"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 700940d1556b..39c794b8971c 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ອະນຸຍາດໃຫ້ຜູ້ຖືເລີ່ມການເບິ່ງຂໍ້ມູນຄຸນສົມບັດສຳລັບແອັບໃດໜຶ່ງ."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີໃນອັດຕາຕົວຢ່າງສູງ"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ອະນຸຍາດໃຫ້ແອັບສຸ່ມຕົວຢ່າງຂໍ້ມູນເຊັນເຊີໃນອັດຕາທີ່ຫຼາຍກວ່າ 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"ຄວບຄຸມຄວາມຍາວ ແລະຕົວອັກສອນທີ່ອະນຸຍາດໃຫ້ຢູ່ໃນລະຫັດລັອກໜ້າຈໍ ແລະ PIN."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 86b890398c8a..20e1f87d254b 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Savininkui leidžiama pradėti programos funkcijų informacijos peržiūrą."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pasiekti jutiklių duomenis dideliu skaitmeninimo dažniu"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Programai leidžiama skaitmeninti jutiklių duomenis didesniu nei 200 Hz dažniu"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Nustatyti slaptažodžio taisykles"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Valdykite, kokio ilgio ekrano užrakto slaptažodžius ir PIN kodus galima naudoti."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Stebėti bandymus atrakinti ekraną"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 123e43aec85b..14df78f0f4ed 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Lietotne ar šo atļauju var skatīt informāciju par citas lietotnes funkcijām."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"piekļuve sensoru datiem, izmantojot augstu iztveršanas frekvenci"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Ļauj lietotnei iztvert sensoru datus, izmantojot frekvenci, kas ir augstāka par 200 Hz."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Paroles kārtulu iestatīšana"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrolēt ekrāna bloķēšanas paroļu un PIN garumu un tajos atļautās rakstzīmes."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 746f06fc1b70..9133d2aed1c8 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"му дозволува на сопственикот да почне со прегледување на податоците за функциите за некоја апликација"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"пристапува до податоците со висока фреквенција на семпл"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Дозволува апликацијата да пристапува до податоците од сензорите со фреквенција на семпл поголема од 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Постави правила за лозинката"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Контролирај ги должината и знаците што се дозволени за лозинки и PIN-броеви за отклучување екран."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Следи ги обидите за отклучување на екранот"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 69c96f3c320f..3e1cef62005d 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ആപ്പിനുള്ള ഫീച്ചറുകളുടെ വിവരങ്ങൾ കാണാൻ ആരംഭിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ഉയർന്ന സാംപ്ലിംഗ് റേറ്റിൽ സെൻസർ ഡാറ്റ ആക്സസ് ചെയ്യുക"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz-നേക്കാൾ ഉയർന്ന റേറ്റിൽ സെൻസർ ഡാറ്റ സാമ്പിൾ ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"പാസ്വേഡ് നിയമങ്ങൾ സജ്ജീകരിക്കുക"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"സ്ക്രീൻ ലോക്ക് പാസ്വേഡുകളിലും PIN-കളിലും അനുവദിച്ചിരിക്കുന്ന ദൈർഘ്യവും പ്രതീകങ്ങളും നിയന്ത്രിക്കുക."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"സ്ക്രീൻ അൺലോക്ക് ശ്രമങ്ങൾ നിരീക്ഷിക്കുക"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 18aa7bc40d4d..1b578976b955 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Аппын онцлогуудын мэдээллийг үзэж эхлэхийг эзэмшигчид зөвшөөрдөг."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"түүврийн өндөр хувиар мэдрэгчийн өгөгдөлд хандах"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Аппад 200 Гц-ээс их хувиар мэдрэгчийн өгөгдлийг түүвэрлэх боломжийг олгодог"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Нууц үгний дүрмийг тохируулах"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Дэлгэц түгжих нууц үг болон ПИН кодны урт болон нийт тэмдэгтийн уртыг хянах."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Дэлгэцийн түгжээг тайлах оролдлогыг хянах"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index e1b45f923b0d..2a4b08e67e6c 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -644,7 +644,7 @@ <string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फिंगरप्रिंट ओळखले नाही"</string> <string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string> <string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"चेहरा ऑथेंटिकेशन केलेला आहे"</string> - <string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"चेहरा ऑथेंटिकेशन केलेला आहे, कृपया कंफर्म दाबा"</string> + <string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"चेहरा ऑथेंटिकेशन केलेला आहे, कृपया कंफर्म प्रेस करा"</string> <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"फिंगरप्रिंट हार्डवेअर उपलब्ध नाही."</string> <string name="fingerprint_error_no_space" msgid="7285481581905967580">"फिंगरप्रिंट सेट करता आली नाही"</string> <string name="fingerprint_error_timeout" msgid="7361192266621252164">"फिंगरप्रिट सेट करण्याची वेळ संपली आहे. पुन्हा प्रयत्न करा."</string> @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"होल्डरला ॲपसाठी वैशिष्ट्यांची माहिती पाहण्यास सुरू करण्याची अनुमती देते."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"उच्च नमुना दराने सेन्सर डेटा अॅक्सेस करते"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ॲपला २०० Hz पेक्षा जास्त दराने सेन्सर डेटाचा नमुना तयार करण्याची अनुमती देते"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियम सेट करा"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रीन लॉक पासवर्ड आणि पिन मध्ये अनुमती दिलेले लांबी आणि वर्ण नियंत्रित करा."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"स्क्रीन अनलॉक प्रयत्नांचे परीक्षण करा"</string> @@ -958,12 +962,12 @@ <string name="keyguard_password_enter_password_code" msgid="2751130557661643482">"अनलॉक करण्यासाठी पासवर्ड टाइप करा"</string> <string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"अनलॉक करण्यासाठी पिन टाइप करा"</string> <string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"अयोग्य पिन कोड."</string> - <string name="keyguard_label_text" msgid="3841953694564168384">"अनलॉक करण्यासाठी, मेनू दाबा नंतर 0."</string> + <string name="keyguard_label_text" msgid="3841953694564168384">"अनलॉक करण्यासाठी, आधी मेनू व नंतर 0 प्रेस करा."</string> <string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"आणीबाणीचा नंबर"</string> <string name="lockscreen_carrier_default" msgid="6192313772955399160">"सेवा नाही"</string> <string name="lockscreen_screen_locked" msgid="7364905540516041817">"स्क्रीन लॉक केली."</string> - <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलॉक करण्यासाठी मेनू दाबा किंवा आणीबाणीचा कॉल करा."</string> - <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलॉक करण्यासाठी मेनू दाबा."</string> + <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलॉक करण्यासाठी मेनू प्रेस करा किंवा आणीबाणीचा कॉल करा."</string> + <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलॉक करण्यासाठी मेनू प्रेस करा."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलॉक करण्यासाठी पॅटर्न काढा"</string> <string name="lockscreen_emergency_call" msgid="7500692654885445299">"आणीबाणी"</string> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉलवर परत या"</string> @@ -1687,7 +1691,7 @@ <string name="csd_entering_RS2_warning" product="default" msgid="3699509945325496807">"तुम्ही ज्या पातळीवर मीडिया ऐकत आहात, असे जास्त कालावधीसाठी सुरू राहिल्याचा परिणाम म्हणून तुमच्या श्रवणशक्तीचे कायमचे नुकसान होऊ शकते.\n\nया पातळीवर जास्त कालावधीसाठी प्ले करणे पुढे सुरू ठेवल्यामुळे तुमच्या श्रवणशक्तीचे नुकसान होऊ शकते."</string> <string name="csd_momentary_exposure_warning" product="default" msgid="7861896191081176454">"चेतावणी,\nतुम्ही सध्या असुरक्षित पातळीवर प्ले होणारा मोठ्या आवाजातील आशय ऐकत आहात.\n\nएवढ्या मोठ्याने ऐकणे पुढे सुरू ठेवणे तुमच्या श्रवणशक्तीचे कायमचे नुकसान करेल."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"प्रवेशयोग्यता शॉर्टकट वापरायचा?"</string> - <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट सुरू असताना, दोन्ही व्हॉल्यूम बटणे तीन सेकंदांसाठी दाबून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्य सुरू होईल."</string> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट सुरू असताना, दोन्ही व्हॉल्यूम बटणे तीन सेकंदांसाठी प्रेस करून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्य सुरू होईल."</string> <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"अॅक्सेसिबिलिटी वैशिष्ट्यांसाठी शॉर्टकट सुरू करायचा आहे का?"</string> <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"दोन्ही व्हॉल्यूम की काही सेकंद धरून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्ये सुरू होतात. यामुळे तुमचे डिव्हाइस कसे काम करते हे पूर्णपणे बदलते.\n\nसध्याची वैशिष्ट्ये:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतुम्ही हा शॉर्टकट सेटिंग्ज > अॅक्सेसिबिलिटी मध्ये बदलू शकता."</string> <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string> @@ -1702,7 +1706,7 @@ <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रीन पहा आणि नियंत्रित करा"</string> <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ते स्क्रीनवरील सर्व आशय वाचू शकते आणि इतर ॲप्सवर आशय प्रदर्शित करू शकते."</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"पहा आणि क्रिया करा"</string> - <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"हे तुम्ही ॲप किंवा हार्डवेअर सेन्सर कसे वापरता ते ट्रॅक करू शकते आणि इतर ॲप्ससोबत तुमच्या वतीने संवाद साधू शकते."</string> + <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"हे तुमचा ॲप किंवा हार्डवेअर सेन्सरसोबतचा परस्परसंवाद ट्रॅक करू शकते आणि इतर ॲप्ससोबत तुमच्या वतीने संवाद साधू शकते."</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमती द्या"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"नकार द्या"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"वैशिष्ट्य वापरणे सुरू करण्यासाठी त्यावर टॅप करा:"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index faf3b0c6ddc1..61e4c34f70d0 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Membenarkan pemegang mula melihat maklumat ciri untuk apl."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"akses data penderia pada data pensampelan yang tinggi"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Membenarkan apl mengambil sampel data penderia pada kadar yang lebih besar daripada 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Tetapkan peraturan kata laluan"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan dan PIN kunci skrin."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Pantau percubaan buka kunci skrin"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index da4ff15baa3f..70cb8c12254f 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ဝန်ဆောင်မှုအချက်အလက်ကိုများကို ခွင့်ပြုချက်ရထားသည့် အက်ပ်အား စတင်ကြည့်နိုင်ရန် ခွင့်ပြုသည်။"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"နမူနာနှုန်းမြင့်သော အာရုံခံစနစ်ဒေတာကို သုံးပါ"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"၂၀၀ Hz နှုန်းထက်ပိုများသော အာရုံခံစနစ်ဒေတာကို နမူနာယူရန် အက်ပ်အား ခွင့်ပြုပါ"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"စကားဝှက်စည်းမျဥ်းကိုသတ်မှတ်ရန်"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"မျက်နှာပြင်သော့ခတ်သည့် စကားဝှက်များနှင့် PINများရှိ ခွင့်ပြုထားသည့် စာလုံးအရေအတွက်နှင့် အက္ခရာများအား ထိန်းချုပ်ရန်။"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"မျက်နှာပြင်လော့ခ်ဖွင့်ရန် ကြိုးပမ်းမှုများကို စောင့်ကြည့်ပါ"</string> @@ -1489,7 +1493,7 @@ <string name="forward_intent_to_work" msgid="3620262405636021151">"သင်သည် ဒီအက်ပ်ကို သင်၏ အလုပ် ပရိုဖိုင် ထဲမှာ အသုံးပြုနေသည်"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"ထည့်သွင်းရန်နည်းလမ်း"</string> <string name="sync_binding_label" msgid="469249309424662147">"ထပ်တူ ကိုက်ညီခြင်း"</string> - <string name="accessibility_binding_label" msgid="1974602776545801715">"အသုံးပြုခွင့်"</string> + <string name="accessibility_binding_label" msgid="1974602776545801715">"အများသုံးနိုင်မှု"</string> <string name="wallpaper_binding_label" msgid="1197440498000786738">"နောက်ခံ"</string> <string name="chooser_wallpaper" msgid="3082405680079923708">"နောက်ခံပြောင်းခြင်း"</string> <string name="notification_listener_binding_label" msgid="2702165274471499713">"အကြောင်းကြားချက် နားတောင်သူ"</string> @@ -1686,10 +1690,10 @@ <string name="csd_dose_repeat_warning" product="default" msgid="6765471037071089401">"သတိပေးချက်-\nတစ်ပတ်တာအတွင်း နားကြပ်ဖြင့် ဘေးကင်းကင်း အသံကျယ်လောင်စွာ နားထောင်နိုင်သည့် ပမာဏထက် ၅ ဆ ကျော်လွန်သွားပါပြီ။\n\nသင့်အကြားအာရုံကို မထိခိုက်စေရန် အသံတိုးလိုက်သည်။"</string> <string name="csd_entering_RS2_warning" product="default" msgid="3699509945325496807">"မီဒီယာကို ယခုနားထောင်သည့်အဆင့်ဖြင့် အချိန်ကြာမြင့်စွာ နားထောင်ပါက အကြားအာရုံကို ထိခိုက်နိုင်သည်။\n\nဤအဆင့်ဖြင့် အချိန်ကြာမြင့်စွာ ဆက်ဖွင့်ခြင်းက သင့်အကြားအာရုံကို ထိခိုက်စေနိုင်သည်။"</string> <string name="csd_momentary_exposure_warning" product="default" msgid="7861896191081176454">"သတိပေးချက်-\nသင်သည် ကျယ်လောင်သော အကြောင်းအရာကို အန္တရာယ်ရှိသောအဆင့်ဖြင့် လက်ရှိဖွင့်ထားသည်။\n\nဤသို့ကျယ်လောင်စွာ ဆက်လက်နားထောင်ခြင်းက သင့်အကြားအာရုံကို ထာဝရထိခိုက်စေမည်။"</string> - <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုလိုပါသလား။"</string> + <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"အများသုံးနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုလိုပါသလား။"</string> <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံထိန်းခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးနိုင်သည့် ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။"</string> <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများအတွက် ဖြတ်လမ်းကို ဖွင့်မလား။"</string> - <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nလက်ရှိ ဝန်ဆောင်မှုများ-\n<xliff:g id="SERVICE">%1$s</xliff:g>\n\'ဆက်တင်များ > အများသုံးစွဲနိုင်မှု\' တွင် ရွေးထားသည့် ဝန်ဆောင်မှုများကို ပြောင်းနိုင်သည်။"</string> + <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nလက်ရှိ ဝန်ဆောင်မှုများ-\n<xliff:g id="SERVICE">%1$s</xliff:g>\n\'ဆက်တင်များ > အများသုံးနိုင်မှု\' တွင် ရွေးထားသည့် ဝန်ဆောင်မှုများကို ပြောင်းနိုင်သည်။"</string> <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string> <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ဖြတ်လမ်းကို ဖွင့်မလား။"</string> <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးနိုင်သည့် ဝန်ဆောင်မှုဖြစ်သော <xliff:g id="SERVICE">%1$s</xliff:g> ကို ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nဤဖြတ်လမ်းလင့်ခ်ကို ဆက်တင်များ > အများသုံးနိုင်မှုတွင် နောက်ဝန်ဆောင်မှုတစ်ခုသို့ ပြောင်းနိုင်သည်။"</string> @@ -1698,7 +1702,7 @@ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"ဖွင့်"</string> <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"ပိတ်"</string> <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> ကို သင့်စက်အား အပြည့်အဝထိန်းချုပ်ခွင့် ပေးလိုပါသလား။"</string> - <string name="accessibility_service_warning_description" msgid="291674995220940133">"အများသုံးစွဲနိုင်မှု လိုအပ်ချက်များအတွက် အထောက်အကူပြုသည့် အက်ပ်များအား အပြည့်အဝ ထိန်းချုပ်ခွင့်ပေးခြင်းသည် သင့်လျော်သော်လည်း အက်ပ်အများစုအတွက် မသင့်လျော်ပါ။"</string> + <string name="accessibility_service_warning_description" msgid="291674995220940133">"အများသုံးနိုင်မှု လိုအပ်ချက်များအတွက် အထောက်အကူပြုသည့် အက်ပ်များအား အပြည့်အဝ ထိန်းချုပ်ခွင့်ပေးခြင်းသည် သင့်လျော်သော်လည်း အက်ပ်အများစုအတွက် မသင့်လျော်ပါ။"</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"ဖန်သားပြင်ကို ကြည့်ရှုထိန်းချုပ်ခြင်း"</string> <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"၎င်းသည် မျက်နှာပြင်ပေါ်ရှိ အကြောင်းအရာအားလုံးကို ဖတ်နိုင်ပြီး အခြားအက်ပ်များအပေါ်တွင် အကြောင်းအရာကို ဖော်ပြနိုင်သည်။"</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"လုပ်ဆောင်ချက်များကို ကြည့်ရှုဆောင်ရွက်ခြင်း"</string> @@ -1706,7 +1710,7 @@ <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"ခွင့်ပြုရန်"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"ပယ်ရန်"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"ဝန်ဆောင်မှုကို စတင်အသုံးပြုရန် တို့ပါ−"</string> - <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"အများသုံးစွဲနိုင်မှု ခလုတ်ဖြင့် အသုံးပြုရန် ဝန်ဆောင်မှုများကို ရွေးပါ"</string> + <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"အများသုံးနိုင်မှု ခလုတ်ဖြင့် အသုံးပြုရန် ဝန်ဆောင်မှုများကို ရွေးပါ"</string> <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"အသံခလုတ် ဖြတ်လမ်းလင့်ခ်ဖြင့် အသုံးပြုရန် ဝန်ဆောင်မှုများကို ရွေးပါ"</string> <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ကို ပိတ်ထားသည်"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ဖြတ်လမ်းများကို တည်းဖြတ်ရန်"</string> @@ -2005,7 +2009,7 @@ <string name="app_category_news" msgid="1172762719574964544">"သတင်းနှင့် မဂ္ဂဇင်းများ"</string> <string name="app_category_maps" msgid="6395725487922533156">"မြေပုံနှင့် ခရီးလမ်းညွှန်ချက်"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ထုတ်လုပ်နိုင်မှု"</string> - <string name="app_category_accessibility" msgid="6643521607848547683">"အများသုံးစွဲနိုင်မှု"</string> + <string name="app_category_accessibility" msgid="6643521607848547683">"အများသုံးနိုင်မှု"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"စက်ပစ္စည်း သိုလှောင်ခန်း"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB အမှားရှာပြင်ခြင်း"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"နာရီ"</string> @@ -2139,7 +2143,7 @@ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"မိုက်ခွက်ပါနားကြပ်ချိတ်"</string> <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ဖန်သားပြင်အတွက် အများသုံးစွဲနိုင်မှုဖြတ်လမ်းလင့်ခ်"</string> <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ဖန်သားပြင်အတွက် အများသုံးစွဲနိုင်မှုဖြတ်လမ်းလင့်ခ် ရွေးချယ်စနစ်"</string> - <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်"</string> + <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"အများသုံးနိုင်မှု ဖြတ်လမ်းလင့်ခ်"</string> <string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"အကြောင်းကြားစာအကွက်ကို ပယ်ရန်"</string> <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad အပေါ်"</string> <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad အောက်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 2f59013107a2..826c1c1adda3 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Lar innehaveren se informasjon om funksjonene for en app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"tilgang til sensordata ved høy samplingfrekvens"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Lar appen samle inn sensordata ved en hastighet som er høyere enn 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Angi passordregler"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrollerer tillatt lengde og tillatte tegn i passord og PIN-koder for opplåsing av skjermen."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Overvåk forsøk på å låse opp skjermen"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruker begge skjermene til å vise innhold"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Enheten er for varm"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dobbel skjerm er ikke tilgjengelig fordi telefonen begynner å bli for varm"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen er ikke tilgjengelig"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen er ikke tilgjengelig fordi Batterisparing er slått på. Du kan slå av denne funksjonen i innstillingene."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Gå til innstillingene"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Slå av"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> er konfigurert"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Tastaturoppsettet er satt til <xliff:g id="LAYOUT_1">%s</xliff:g>. Trykk for å endre det."</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 52775d00fcb2..f6de5f5ed42b 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"होल्डरलाई एपका सुविधासम्बन्धी जानकारी हेर्न दिन्छ।"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"नमुना लिने उच्च दरमा सेन्सरसम्बन्धी डेटा प्रयोग गर्ने"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"यो अनुमति दिइएमा एपले २०० हर्जभन्दा बढी दरमा सेन्सरसम्बन्धी डेटाको नमुना लिन सक्छ"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियमहरू मिलाउनुहोस्"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रिन लक पासवर्ड र PIN हरूमा अनुमति दिइएको लम्बाइ र वर्णहरूको नियन्त्रण गर्नुहोस्।"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"मनिटरको स्क्रिन अनलक गर्ने प्रयासहरू"</string> @@ -1704,7 +1708,7 @@ <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"कारबाहीहरू हेर्नुहोस् र तिनमा कार्य गर्नुहोस्"</string> <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"यसले कुनै एप वा हार्डवेयर सेन्सरसँग तपाईंले गर्ने अन्तर्क्रियाको ट्र्याक गर्न सक्छ र तपाईंका तर्फबाट एपहरूसँग अन्तर्क्रिया गर्न सक्छ।"</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमति दिनुहोस्"</string> - <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"इन्कार गर्नु⋯"</string> + <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"नदिनुहोस्"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"कुनै सुविधा प्रयोग गर्न थाल्न उक्त सुविधामा ट्याप गर्नुहोस्:"</string> <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"पहुँचको बटनमार्फत प्रयोग गर्न चाहेका सुविधाहरू छनौट गर्नुहोस्"</string> <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"भोल्युम कुञ्जीको सर्टकटमार्फत प्रयोग गर्न चाहेका सुविधाहरू छनौट गर्नुहोस्"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 64ae8147646b..ddd55728fa08 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Hiermee kan de houder informatie over functies bekijken voor een app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"toegang krijgen tot sensorgegevens met een hoge samplingsnelheid"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Hiermee kan de app sensorgegevens samplen met een snelheid die hoger is dan 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Wachtwoordregels instellen"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"De lengte en het aantal tekens beheren die zijn toegestaan in wachtwoorden en pincodes voor schermvergrendeling."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Pogingen voor schermontgrendeling bijhouden"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 09ae2629379b..1470c19a78d5 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"କୌଣସି ଆପ ପାଇଁ ଫିଚରଗୁଡ଼ିକ ବିଷୟରେ ସୂଚନା ଦେଖିବା ଆରମ୍ଭ କରିବାକୁ ହୋଲଡରଙ୍କୁ ଅନୁମତି ଦିଏ।"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ଏକ ଉଚ୍ଚ ନମୁନାକରଣ ରେଟରେ ସେନ୍ସର୍ ଡାଟାକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz ଠାରୁ ଅଧିକ ଏକ ରେଟରେ ସେନ୍ସର୍ ଡାଟାର ନମୁନା ନେବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"ପାସ୍ୱର୍ଡ ନିୟମାବଳୀ ସେଟ୍ କରନ୍ତୁ"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"ଲକ୍ ସ୍କ୍ରୀନ୍ ପାସ୍ୱର୍ଡ ଓ PINରେ ଅନୁମୋଦିତ ଦୀର୍ଘତା ଓ ବର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"ସ୍କ୍ରୀନ୍-ଅନଲକ୍ କରିବା ଉଦ୍ୟମ ନୀରିକ୍ଷଣ କରନ୍ତୁ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 6ec3eda46ba2..62c2b83964c4 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ਇਸ ਨਾਲ ਹੋਲਡਰ ਨੂੰ ਕਿਸੇ ਐਪ ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਬਾਰੇ ਜਾਣਕਾਰੀ ਦੇਖਣ ਦੀ ਆਗਿਆ ਮਿਲਦੀ ਹੈ।"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ਉੱਚ ਸੈਂਪਲਿੰਗ ਰੇਟ \'ਤੇ ਸੈਂਸਰ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ਐਪ ਨੂੰ 200 Hz ਤੋਂ ਵੱਧ ਦੀ ਦਰ \'ਤੇ ਸੈਂਸਰ ਡਾਟੇ ਦਾ ਨਮੂਨਾ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"ਪਾਸਵਰਡ ਨਿਯਮ ਸੈੱਟ ਕਰੋ"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"ਸਕ੍ਰੀਨ ਲਾਕ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਿੰਨ ਵਿੱਚ ਆਗਿਆ ਦਿੱਤੀ ਲੰਮਾਈ ਅਤੇ ਅੱਖਰਾਂ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ।"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"ਸਕ੍ਰੀਨ ਅਣਲਾਕ ਕਰਨ ਦੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ \'ਤੇ ਨਿਗਰਾਨੀ ਰੱਖੋ"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਸਮੱਗਰੀ ਨੂੰ ਦਿਖਾਉਣ ਲਈ ਦੋਵੇਂ ਡਿਸਪਲੇਆਂ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀ ਹੈ"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ਡੀਵਾਈਸ ਬਹੁਤ ਗਰਮ ਹੈ"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ਦੋਹਰੀ ਸਕ੍ਰੀਨ ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬੰਦ ਕਰ ਸਕਦੇ ਹੋ।"</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ਬੰਦ ਕਰੋ"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ਦਾ ਸੰਰੂਪਣ ਕੀਤਾ ਗਿਆ"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"ਕੀ-ਬੋਰਡ ਦਾ ਖਾਕਾ <xliff:g id="LAYOUT_1">%s</xliff:g> \'ਤੇ ਸੈੱਟ ਹੈ। ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 274af139f5d2..efc142165483 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Umożliwia posiadaczowi rozpoczęcie przeglądania informacji o funkcjach aplikacji."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"dostęp do danych czujnika z wysoką częstotliwością"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Zezwala aplikacji na pobieranie próbek danych z czujnika z częstotliwością wyższą niż 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Określ reguły hasła"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrolowanie długości haseł blokady ekranu i kodów PIN oraz dozwolonych w nich znaków."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitorowanie prób odblokowania ekranu"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 6d4419652873..052f9696f045 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que o sistema comece a ver as informações de recursos de um app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"acessar os dados do sensor em uma taxa de amostragem elevada"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que o app receba amostras de dados do sensor em uma taxa maior que 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Definir regras para senha"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controla o tamanho e os caracteres permitidos nos PINs e nas senhas do bloqueio de tela."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitorar tentativas de desbloqueio de tela"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index ff4fe09c36f8..9dd104c1f575 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que o titular comece a ver as informações das funcionalidades de uma app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"aceder aos dados de sensores a uma taxa de amostragem elevada"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que a app obtenha uma amostra dos dados de sensores a uma taxa superior a 200 Hz."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Definir regras de palavra-passe"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controlar o comprimento e os carateres permitidos nos PINs e nas palavras-passe do bloqueio de ecrã."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitorizar tentativas de desbloqueio do ecrã"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 6d4419652873..052f9696f045 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que o sistema comece a ver as informações de recursos de um app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"acessar os dados do sensor em uma taxa de amostragem elevada"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que o app receba amostras de dados do sensor em uma taxa maior que 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Definir regras para senha"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Controla o tamanho e os caracteres permitidos nos PINs e nas senhas do bloqueio de tela."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitorar tentativas de desbloqueio de tela"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index b425883d48d7..871aeb9bc90a 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite proprietarului să înceapă să vadă informațiile despre funcții pentru o aplicație."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"să acceseze date de la senzori la o rată de eșantionare mare"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite aplicației să colecteze date de la senzori la o rată de eșantionare de peste 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Să seteze reguli pentru parolă"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Stabilește lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Să monitorizeze încercările de deblocare a ecranului"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index eccd18daac69..168dfcbf18be 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Позволяет просматривать информацию о функциях приложения."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Доступ к данным датчиков при высокой частоте дискретизации"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Приложение сможет считывать данные датчиков на частоте более 200 Гц."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Настройка правил для паролей"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Контролировать длину и символы при вводе пароля и PIN-кода."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Отслеживание попыток разблокировать экран"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 01b04ec08354..bdcf9300d125 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"යෙදුමක් සඳහා විශේෂාංග තොරතුරු බැලීම ආරම්භ කිරීමට දරන්නාට ඉඩ දෙන්න."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ඉහළ නියැදි කිරීමේ වේගයකින් සංවේදක දත්ත වෙත පිවිසෙන්න"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz ට වඩා වැඩි වේගයකින් සංවේදක දත්ත නියැදි කිරීමට යෙදුමට ඉඩ දෙයි"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"මුරපද නීති සකස් කිරීම"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"තිර අගුලු මුරපද සහ PIN තුළ ඉඩ දෙන දිග සහ අනුලකුණු පාලනය කිරීම."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"තිරය අගුළු ඇරීමේ උත්සාහයන් නිරීක්ෂණය කරන්න"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"අන්තර්ගතය පෙන්වීමට <xliff:g id="APP_NAME">%1$s</xliff:g> සංදර්ශන දෙකම භාවිත කරයි"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"උපාංගය ඉතා උණුසුම් වේ"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ඔබේ දුරකථනය ඉතා උණුසුම් නිසා ද්විත්ව තිරය ලබා ගත නොහැක"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen නොමැත"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"බැටරි සුරැකුම ක්රියාත්මක නිසා Dual Screen නොමැත. ඔබට මෙය සැකසීම් තුළ ක්රියාවිරහිත කළ හැක."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"සැකසීම් වෙත යන්න"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"අක්රිය කරන්න"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> වින්යාස කෙරිණි"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"යතුරු පුවරු පිරිසැලසුම <xliff:g id="LAYOUT_1">%s</xliff:g> ලෙස සැකසිණි. වෙනස් කිරීමට තට්ටු කරන්න."</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 289489695bb5..4d4c084aee41 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Umožňuje držiteľovi zobraziť informácie o funkciách aplikácie."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"prístup k dátam senzorom s vysokou vzorkovacou frekvenciou"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Umožňuje aplikácii vzorkovať dáta senzorov s frekvenciou vyššou ako 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Nastaviť pravidlá pre heslo"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Nastavte dĺžku hesiel na odomknutie obrazovky aj kódov PIN a v nich používané znaky."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Sledovanie pokusov o odomknutie obrazovky"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 6d1d8b0f5560..d8dd26871c20 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Imetniku omogoča začetek ogledovanja informacij o funkcijah poljubne aplikacije."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"dostop do podatkov tipal z večjo hitrostjo vzorčenja"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Aplikaciji dovoljuje, da vzorči podatke tipal s hitrostjo, večjo od 200 Hz."</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Nastavitev pravil za geslo"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih in kodah PIN za odklepanje zaslona."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Nadzor nad poskusi odklepanja zaslona"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index fc94221e7b76..c97713ee30b1 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Lejon që zotëruesi të fillojë të shikojë informacionin e veçorive për një aplikacion."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"qasu te të dhënat e sensorit me një shpejtësi kampionimi më të lartë"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Lejon aplikacionin të mbledhë shembujt e të dhënave të sensorit me shpejtësi më të lartë se 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Cakto rregullat e fjalëkalimit"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrollo gjatësinë dhe karakteret e lejuara në fjalëkalimet dhe kodet PIN të kyçjes së ekranit."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitoro tentativat e shkyçjes së ekranit"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index deb4476bb246..91ea24ab21ab 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -801,6 +801,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Дозвољава носиоцу дозволе да започне прегледање информација о функцијама апликације."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"приступ подацима сензора при великој брзини узорковања"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Дозвољава апликацији да узима узорак података сензора при брзини већој од 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Подешавање правила за лозинку"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Контролише дужину и знакове дозвољене у лозинкама и PIN-овима за закључавање екрана."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Надгледајте покушаје откључавања екрана"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 823c83640f2a..57c31dba6bc2 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Tillåter att innehavaren börjar visa information om funktioner för en app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"åtkomst till sensordata med en hög samplingsfrekvens"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Tillåter att appen får åtkomst till sensordata med en högre samplingsfrekvens än 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Ange lösenordsregler"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Styr tillåten längd och tillåtna tecken i lösenord och pinkoder för skärmlåset."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Övervaka försök att låsa upp skärmen"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> använder båda skärmarna för att visa innehåll"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Enheten är för varm"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dubbel skärm kan inte användas eftersom telefonen börjar bli för varm"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen är inte tillgängligt"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen kan inte användas eftersom battersparläget är aktiverat. Du kan inaktivera detta i inställningarna."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Öppna inställningarna"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Stäng av"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> har konfigurerats"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Tangentbordslayouten har ställts in på <xliff:g id="LAYOUT_1">%s</xliff:g>. Tryck om du vill ändra."</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index e8861fde8d4f..ec5f4f778c1c 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Huruhusu mmiliki kuanza kuangalia maelezo ya vipengele vya programu."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"fikia data ya vitambuzi kwa kasi ya juu ya sampuli"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Huruhusu programu kujaribu sampuli ya data ya vitambuzi kwa kasi inayozidi Hz 200"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Kuweka kanuni za nenosiri"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Dhibiti urefu na maandishi yanayokubalika katika nenosiri la kufunga skrini na PIN."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Kuhesabu mara ambazo skrini inajaribu kufunguliwa"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 6c3591e95123..012444eedf79 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ஆப்ஸின் அம்சங்கள் குறித்த தகவல்களைப் பார்ப்பதற்கான அனுமதியை ஹோல்டருக்கு வழங்கும்."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"அதிகளவிலான சாம்பிளிங் ரேட்டில் சென்சார் தரவை அணுகுதல்"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 ஹெர்ட்ஸ்க்கும் அதிகமான வீதத்தில் சென்சார் தரவை மாதிரியாக்க ஆப்ஸை அனுமதிக்கும்"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"கடவுச்சொல் விதிகளை அமைக்கவும்"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"திரைப் பூட்டின் கடவுச்சொற்கள் மற்றும் பின்களில் அனுமதிக்கப்படும் நீளத்தையும் எழுத்துக்குறிகளையும் கட்டுப்படுத்தும்."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"திரையை அன்லாக் செய்வதற்கான முயற்சிகளைக் கண்காணி"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"உள்ளடக்கத்தைக் காட்டுவதற்கு இரண்டு டிஸ்ப்ளேக்களையும் <xliff:g id="APP_NAME">%1$s</xliff:g> பயன்படுத்துகிறது"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"சாதனம் மிகவும் சூடாக உள்ளது"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"உங்கள் மொபைல் மிகவும் சூடாக இருப்பதால் இரட்டைத் திரை அம்சத்தைப் பயன்படுத்த முடியாது"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen அம்சத்தைப் பயன்படுத்த முடியாது"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"பேட்டரி சேமிப்பான் இயக்கத்தில் இருப்பதால் Dual Screen அம்சத்தைப் பயன்படுத்த முடியாது. இதை நீங்கள் அமைப்புகளில் முடக்கலாம்."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"அமைப்புகளைத் திற"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"முடக்கு"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> சாதனம் உள்ளமைக்கப்பட்டது"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"கீபோர்டு தளவமைப்பு <xliff:g id="LAYOUT_1">%s</xliff:g> மொழியில் அமைக்கப்பட்டது. மாற்ற தட்டவும்."</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index dce037768574..211066707da4 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"యాప్ ఫీచర్ల సమాచారాన్ని చూడటాన్ని ప్రారంభించడానికి హోల్డర్ను అనుమతిస్తుంది."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"అధిక శాంపిల్ రేటు వద్ద సెన్సార్ డేటాను యాక్సెస్ చేయండి"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz కంటే ఎక్కువ రేట్ వద్ద శాంపిల్ సెన్సార్ డేటాకు యాప్ను అనుమతిస్తుంది"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"పాస్వర్డ్ నియమాలను సెట్ చేయండి"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"స్క్రీన్ లాక్ పాస్వర్డ్లు మరియు PINల్లో అనుమతించబడిన పొడవు మరియు అక్షరాలను నియంత్రిస్తుంది."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"స్క్రీన్ అన్లాక్ ప్రయత్నాలను పర్యవేక్షించండి"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index eef7772803e5..116e31e8fe5b 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"อนุญาตให้เจ้าของเริ่มดูข้อมูลฟีเจอร์สำหรับแอป"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"เข้าถึงข้อมูลเซ็นเซอร์ที่อัตราการสุ่มตัวอย่างสูง"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"อนุญาตให้แอปสุ่มตัวอย่างข้อมูลเซ็นเซอร์ที่อัตราสูงกว่า 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"ตั้งค่ากฎรหัสผ่าน"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"ควบคุมความยาวและอักขระที่สามารถใช้ในรหัสผ่านของการล็อกหน้าจอและ PIN"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index d2137f64ccb3..b31e160a7da1 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Nagbibigay-daan sa may hawak na simulang tingnan ang impormasyon ng mga feature para sa isang app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"mag-access ng data ng sensor sa mataas na rate ng pag-sample"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Pinapahintulutan ang app na mag-sample ng data ng sensor sa rate na higit sa 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Magtakda ng mga panuntunan sa password"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrolin ang haba at ang mga character na pinapayagan sa mga password at PIN sa screen lock."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index b2d7617e9867..aaf76445894d 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"İzin sahibinin, bir uygulamanın özellik bilgilerini görüntülemeye başlamasına izin verir."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"sensör verilerine daha yüksek örnekleme hızında eriş"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Uygulamanın, sensör verilerini 200 Hz\'den daha yüksek bir hızda örneklemesine olanak tanır"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Şifre kuralları ayarla"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Ekran kilidini açma şifrelerinde ve PIN\'lerde izin verilen uzunluğu ve karakterleri denetler."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Ekran kilidini açma denemelerini izle"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>, içeriği göstermek için her iki ekranı da kullanıyor"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Cihaz çok ısındı"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Telefonunuz çok ısındığı için Çift Ekran kullanılamıyor"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen kullanılamıyor"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Pil Tasarrufu açık olduğundan Dual Screen kullanılamıyor. Bu özelliği Ayarlar\'dan kapatabilirsiniz."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ayarlar\'a git"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Kapat"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> yapılandırıldı"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Klavye düzeni <xliff:g id="LAYOUT_1">%s</xliff:g> olarak ayarlandı. Değiştirmek için dokunun."</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 9296f6a9e669..edf482ed8e34 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -802,6 +802,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Дозволяє додатку почати перегляд інформації про функції іншого додатка."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"доступ до даних датчиків із високою частотою дикретизації"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Додаток зможе дискретизувати дані даних датчиків із частотою понад 200 Гц"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Устан. правила пароля"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Укажіть максимальну довжину та кількість символів для паролів розблокування екрана та PIN-кодів."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Відстежувати спроби розблокування екрана"</string> @@ -2326,12 +2330,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує обидва екрани для показу контенту"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Пристрій сильно нагрівається"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Подвійний екран недоступний, оскільки телефон сильно нагрівається"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функція Dual Screen недоступна"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функція Dual Screen недоступна, оскільки ввімкнено режим енергозбереження. Її можна вимкнути в налаштуваннях."</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"Перейти до налаштувань"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Вимкнути"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Клавіатуру \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\" налаштовано"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Вибрано розкладку клавіатури \"<xliff:g id="LAYOUT_1">%s</xliff:g>\". Натисніть, щоб змінити."</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 49700501a267..9a1e5c1188fc 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ہولڈر کو ایپ کے لیے خصوصیات کی معلومات دیکھنے کی اجازت دیتا ہے۔"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"نمونہ کاری کی اعلی شرح پر سینسر کے ڈیٹا تک رسائی حاصل کریں"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ایپ کو Hz200 سے زیادہ شرح پر سینسر ڈیٹا کا نمونہ لینے کی اجازت دیتی ہے"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"پاس ورڈ کے اصول سیٹ کریں"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"اسکرین لاک پاس ورڈز اور PINs میں اجازت یافتہ لمبائی اور حروف کو کنٹرول کریں۔"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"اسکرین غیر مقفل کرنے کی کوششیں مانیٹر کریں"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 69b2efb25f2f..e18e7b1bd38d 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Qurilma egasiga ilova funksiyalari axborotini koʻrishga ruxsat beradi."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"yuqori diskretlash chastotali sensor axborotiga ruxsat"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Ilova sensor axborotini 200 Hz dan yuqori tezlikda hisoblashi mumkin"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Parol qoidalarini o‘rnatish"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Ekran qulfi paroli va PIN kodlari uchun qo‘yiladigan talablarni (belgilar soni va uzunligi) nazorat qiladi."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Ekranni qulfdan chiqarishga urinishlarni nazorat qilish"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 93907f9c0582..6dcdb13138ee 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Cho phép chủ sở hữu bắt đầu xem thông tin về tính năng của một ứng dụng."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"truy cập vào dữ liệu cảm biến ở tốc độ lấy mẫu cao"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Cho phép ứng dụng lấy mẫu dữ liệu cảm biến ở tốc độ lớn hơn 200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Đặt quy tắc mật khẩu"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kiểm soát độ dài và ký tự được phép trong mật khẩu khóa màn hình và mã PIN."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Giám sát những lần thử mở khóa màn hình"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 818f1ff39c06..51282d3de6bd 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"允许具有该权限的应用开始查看某个应用的功能信息。"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"以高采样率访问传感器数据"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"允许应用以高于 200 Hz 的频率对传感器数据进行采样"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"设置密码规则"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"控制锁屏密码和 PIN 码所允许的长度和字符。"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"监控屏幕解锁尝试次数"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 67db0604052d..60fcea8178cc 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"允許擁有者開始查看應用程式的功能資料。"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"以高取樣率存取感應器資料"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"允許應用程式以大於 200 Hz 的頻率對感應器資料進行取樣"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"設定密碼規則"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"控制螢幕鎖定密碼和 PIN 所允許的長度和字元。"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"監控螢幕解鎖嘗試次數"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在使用雙螢幕顯示內容"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"裝置過熱"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"由於手機過熱,雙螢幕功能無法使用"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"無法使用雙螢幕功能"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"由於「省電模式」已開啟,因此無法使用雙螢幕功能。您可以前往「設定」中關閉此模式。"</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"前往「設定」"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"關閉"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"已設定「<xliff:g id="DEVICE_NAME">%s</xliff:g>」"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"鍵盤版面配置已設定為<xliff:g id="LAYOUT_1">%s</xliff:g>。輕按即可變更。"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index b3af8e327b0e..0a93c82f728b 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"允許具有這項權限的應用程式開始查看其他應用程式的功能資訊。"</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"以高取樣率存取感應器資料"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"允許應用程式以高於 200 Hz 的頻率對感應器資料進行取樣"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"設定密碼規則"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"管理螢幕鎖定密碼和 PIN 碼支援的字元和長度上限。"</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"監控螢幕解鎖嘗試次數"</string> @@ -2324,12 +2328,9 @@ <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在使用雙螢幕顯示內容"</string> <string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"裝置過熱"</string> <string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"手機過熱,因此無法使用雙螢幕功能"</string> - <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) --> - <skip /> - <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) --> - <skip /> - <!-- no translation found for device_state_notification_settings_button (691937505741872749) --> - <skip /> + <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"無法使用雙螢幕功能"</string> + <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"省電模式已開啟,因此無法使用雙螢幕功能。你可以前往「設定」頁面關閉這個模式。"</string> + <string name="device_state_notification_settings_button" msgid="691937505741872749">"前往「設定」"</string> <string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"停用"</string> <string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"已設定「<xliff:g id="DEVICE_NAME">%s</xliff:g>」"</string> <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"鍵盤配置已設為<xliff:g id="LAYOUT_1">%s</xliff:g>。輕觸即可變更。"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 0f9bde71fabd..b8f4e14d6ce6 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -800,6 +800,10 @@ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Vumela isibambi ukuthi siqale ukubuka ulwazi lwezakhi lwe-app."</string> <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"finyelela idatha yenzwa ngenani eliphezulu lokwenza isampuli"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Ivumela uhlelo lokusebenza lusampule idatha yenzwa ngenani elikhulu kuno-200 Hz"</string> + <!-- no translation found for permlab_updatePackagesWithoutUserAction (3363272609642618551) --> + <skip /> + <!-- no translation found for permdesc_updatePackagesWithoutUserAction (4567739631260526366) --> + <skip /> <string name="policylab_limitPassword" msgid="4851829918814422199">"Misa imithetho yephasiwedi"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi wokukhiya isikrini nama-PIN."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"Qapha imizamo yokuvula isikrini sakho"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 01871ed2b0d0..ef19fc1f5360 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3345,6 +3345,11 @@ <!-- The duration in which a recent task is considered in session and should be visible. --> <integer name="config_activeTaskDurationHours">6</integer> + <!-- Whether this device prefers to show snapshot or splash screen on back predict target. + When set true, there will create windowless starting surface for the preview target, so it + won't affect activity's lifecycle. This should only be disabled on low-ram device. --> + <bool name="config_predictShowStartingSurface">true</bool> + <!-- default window ShowCircularMask property --> <bool name="config_windowShowCircularMask">false</bool> @@ -5218,6 +5223,11 @@ of known compatibility issues. --> <string-array name="config_highRefreshRateBlacklist"></string-array> + <!-- The list of packages to force slowJpegMode for Apps using Camera API1 --> + <string-array name="config_forceSlowJpegModeList" translatable="false"> + <!-- Add packages here --> + </string-array> + <!-- Whether or not to hide the navigation bar when the soft keyboard is visible in order to create additional screen real estate outside beyond the keyboard. Note that the user needs to have a confirmed way to dismiss the keyboard when desired. --> @@ -6352,23 +6362,6 @@ <!-- Package name of Health Connect data migrator application. --> <string name="config_healthConnectMigratorPackageName"></string> - <!-- The Universal Stylus Initiative (USI) protocol version supported by each display. - (@see https://universalstylus.org/). - - The i-th value in this array corresponds to the supported USI version of the i-th display - listed in config_displayUniqueIdArray. On a single-display device, the - config_displayUniqueIdArray may be empty, in which case the only value in this array should - be the USI version for the main built-in display. - - If the display does not support USI, the version value should be an empty string. If the - display supports USI, the version must be in the following format: - "<major-version>.<minor-version>" - - For example, "", "1.0", and "2.0" are valid values. --> - <string-array name="config_displayUsiVersionArray" translatable="false"> - <item>""</item> - </string-array> - <!-- Whether system apps should be scanned in the stopped state during initial boot. Packages can be added by OEMs in an allowlist, to prevent them from being scanned as "stopped" during initial boot of a device, or after an OTA update. Stopped state of diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 6afdae508623..3ee8af2842bf 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2191,6 +2191,11 @@ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this.[CHAR_LIMIT=NONE] --> <string name="permdesc_highSamplingRateSensors">Allows the app to sample sensor data at a rate greater than 200 Hz</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] --> + <string name="permlab_updatePackagesWithoutUserAction">update app without user action</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this.[CHAR_LIMIT=NONE] --> + <string name="permdesc_updatePackagesWithoutUserAction">Allows the holder to update the app it previously installed without user action</string> + <!-- Policy administration --> <!-- Title of policy access to limiting the user's password choices --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 0f4ef4978f05..8855d5b3de25 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -393,6 +393,7 @@ <java-symbol type="integer" name="config_maxNumVisibleRecentTasks" /> <java-symbol type="integer" name="config_activeTaskDurationHours" /> <java-symbol type="bool" name="config_windowShowCircularMask" /> + <java-symbol type="bool" name="config_predictShowStartingSurface" /> <java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" /> <java-symbol type="bool" name="config_supportMicNearUltrasound" /> <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" /> @@ -1476,6 +1477,7 @@ <java-symbol type="layout" name="action_mode_close_item" /> <java-symbol type="layout" name="alert_dialog" /> <java-symbol type="layout" name="cascading_menu_item_layout" /> + <java-symbol type="layout" name="cascading_menu_item_layout_material" /> <java-symbol type="layout" name="choose_account" /> <java-symbol type="layout" name="choose_account_row" /> <java-symbol type="layout" name="choose_account_type" /> @@ -1525,6 +1527,7 @@ <java-symbol type="layout" name="list_content_simple" /> <java-symbol type="layout" name="list_menu_item_checkbox" /> <java-symbol type="layout" name="list_menu_item_icon" /> + <java-symbol type="layout" name="list_menu_item_fixed_size_icon" /> <java-symbol type="layout" name="list_menu_item_layout" /> <java-symbol type="layout" name="list_menu_item_radio" /> <java-symbol type="layout" name="locale_picker_item" /> @@ -4194,6 +4197,7 @@ <java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" /> + <java-symbol type="array" name="config_forceSlowJpegModeList" /> <java-symbol type="layout" name="chooser_dialog" /> <java-symbol type="layout" name="chooser_dialog_item" /> diff --git a/core/tests/coretests/src/android/app/ApplicationLoadersTest.java b/core/tests/coretests/src/android/app/ApplicationLoadersTest.java index 19e7f80dfa5b..3cb62b97647b 100644 --- a/core/tests/coretests/src/android/app/ApplicationLoadersTest.java +++ b/core/tests/coretests/src/android/app/ApplicationLoadersTest.java @@ -16,14 +16,17 @@ package android.app; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import android.content.pm.SharedLibraryInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.google.android.collect.Lists; + import org.junit.Test; import org.junit.runner.RunWith; @@ -48,7 +51,7 @@ public class ApplicationLoadersTest { @Test public void testGetNonExistantLib() { ApplicationLoaders loaders = new ApplicationLoaders(); - assertEquals(null, loaders.getCachedNonBootclasspathSystemLib( + assertNull(loaders.getCachedNonBootclasspathSystemLib( "/system/framework/nonexistantlib.jar", null, null, null)); } @@ -57,9 +60,9 @@ public class ApplicationLoadersTest { ApplicationLoaders loaders = new ApplicationLoaders(); SharedLibraryInfo libA = createLib(LIB_A); - loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA}); + loaders.createAndCacheNonBootclasspathSystemClassLoaders(Lists.newArrayList(libA)); - assertNotEquals(null, loaders.getCachedNonBootclasspathSystemLib( + assertNotNull(loaders.getCachedNonBootclasspathSystemLib( LIB_A, null, null, null)); } @@ -71,9 +74,9 @@ public class ApplicationLoadersTest { ClassLoader parent = ClassLoader.getSystemClassLoader(); assertNotEquals(null, parent); - loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA}); + loaders.createAndCacheNonBootclasspathSystemClassLoaders(Lists.newArrayList(libA)); - assertEquals(null, loaders.getCachedNonBootclasspathSystemLib( + assertNull(loaders.getCachedNonBootclasspathSystemLib( LIB_A, parent, null, null)); } @@ -82,9 +85,9 @@ public class ApplicationLoadersTest { ApplicationLoaders loaders = new ApplicationLoaders(); SharedLibraryInfo libA = createLib(LIB_A); - loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA}); + loaders.createAndCacheNonBootclasspathSystemClassLoaders(Lists.newArrayList(libA)); - assertEquals(null, loaders.getCachedNonBootclasspathSystemLib( + assertNull(loaders.getCachedNonBootclasspathSystemLib( LIB_A, null, "other classloader", null)); } @@ -98,9 +101,9 @@ public class ApplicationLoadersTest { ArrayList<ClassLoader> sharedLibraries = new ArrayList<>(); sharedLibraries.add(dep); - loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA}); + loaders.createAndCacheNonBootclasspathSystemClassLoaders(Lists.newArrayList(libA)); - assertEquals(null, loaders.getCachedNonBootclasspathSystemLib( + assertNull(loaders.getCachedNonBootclasspathSystemLib( LIB_A, null, null, sharedLibraries)); } @@ -112,7 +115,7 @@ public class ApplicationLoadersTest { libB.addDependency(libA); loaders.createAndCacheNonBootclasspathSystemClassLoaders( - new SharedLibraryInfo[]{libA, libB}); + Lists.newArrayList(libA, libB)); ClassLoader loadA = loaders.getCachedNonBootclasspathSystemLib( LIB_A, null, null, null); @@ -121,7 +124,7 @@ public class ApplicationLoadersTest { ArrayList<ClassLoader> sharedLibraries = new ArrayList<>(); sharedLibraries.add(loadA); - assertNotEquals(null, loaders.getCachedNonBootclasspathSystemLib( + assertNotNull(loaders.getCachedNonBootclasspathSystemLib( LIB_DEP_A, null, null, sharedLibraries)); } @@ -132,7 +135,6 @@ public class ApplicationLoadersTest { SharedLibraryInfo libB = createLib(LIB_DEP_A); libB.addDependency(libA); - loaders.createAndCacheNonBootclasspathSystemClassLoaders( - new SharedLibraryInfo[]{libB, libA}); + loaders.createAndCacheNonBootclasspathSystemClassLoaders(Lists.newArrayList(libB, libA)); } } diff --git a/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java b/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java deleted file mode 100644 index f96d138c463b..000000000000 --- a/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.companion.virtual.camera; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.fail; - -import android.graphics.PixelFormat; -import android.hardware.camera2.params.InputConfiguration; -import android.os.ParcelFileDescriptor; -import android.platform.test.annotations.Presubmit; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.ByteArrayInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@Presubmit -@RunWith(AndroidJUnit4.class) -public class VirtualCameraOutputTest { - - private static final String TAG = "VirtualCameraOutputTest"; - - private ExecutorService mExecutor; - - private InputConfiguration mConfiguration; - - @Before - public void setUp() { - mExecutor = Executors.newSingleThreadExecutor(); - mConfiguration = new InputConfiguration(64, 64, PixelFormat.RGB_888); - } - - @After - public void cleanUp() { - mExecutor.shutdownNow(); - } - - @Test - public void createStreamDescriptor_successfulDataStream() { - byte[] cameraData = new byte[]{1, 2, 3, 4, 5}; - VirtualCameraInput input = createCameraInput(cameraData); - VirtualCameraOutput output = new VirtualCameraOutput(input, mExecutor); - ParcelFileDescriptor descriptor = output.getStreamDescriptor(mConfiguration); - - try (FileInputStream fis = new FileInputStream(descriptor.getFileDescriptor())) { - byte[] receivedData = fis.readNBytes(cameraData.length); - - output.closeStream(); - assertThat(receivedData).isEqualTo(cameraData); - } catch (IOException exception) { - fail("Unable to read bytes from FileInputStream. Message: " + exception.getMessage()); - } - } - - @Test - public void createStreamDescriptor_multipleCallsSameStream() { - VirtualCameraInput input = createCameraInput(new byte[]{0}); - VirtualCameraOutput output = new VirtualCameraOutput(input, mExecutor); - - ParcelFileDescriptor firstDescriptor = output.getStreamDescriptor(mConfiguration); - ParcelFileDescriptor secondDescriptor = output.getStreamDescriptor(mConfiguration); - - assertThat(firstDescriptor).isSameInstanceAs(secondDescriptor); - } - - @Test - public void createStreamDescriptor_differentStreams() { - VirtualCameraInput input = createCameraInput(new byte[]{0}); - VirtualCameraOutput callback = new VirtualCameraOutput(input, mExecutor); - - InputConfiguration differentConfig = new InputConfiguration(mConfiguration.getWidth() + 1, - mConfiguration.getHeight() + 1, mConfiguration.getFormat()); - - ParcelFileDescriptor firstDescriptor = callback.getStreamDescriptor(mConfiguration); - ParcelFileDescriptor secondDescriptor = callback.getStreamDescriptor(differentConfig); - - assertThat(firstDescriptor).isNotSameInstanceAs(secondDescriptor); - } - - private VirtualCameraInput createCameraInput(byte[] data) { - return new VirtualCameraInput() { - private ByteArrayInputStream mInputStream = null; - - @Override - @NonNull - public InputStream openStream(@NonNull InputConfiguration inputConfiguration) { - closeStream(); - mInputStream = new ByteArrayInputStream(data); - return mInputStream; - } - - @Override - public void closeStream() { - if (mInputStream == null) { - return; - } - try { - mInputStream.close(); - } catch (IOException e) { - Log.e(TAG, "Unable to close image stream.", e); - } - mInputStream = null; - } - }; - } -} diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java index 6f0c3d306bd5..b0d5240c61ba 100644 --- a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java +++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java @@ -49,6 +49,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; @@ -126,11 +127,11 @@ public class CredentialManagerTest { null, List.of(Slice.HINT_TITLE)).build(); mRegisterRequest = new RegisterCredentialDescriptionRequest( new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL, - "{ \"foo\": \"bar\" }", + new HashSet<>(List.of("{ \"foo\": \"bar\" }")), List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice)))); mUnregisterRequest = new UnregisterCredentialDescriptionRequest( new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL, - "{ \"foo\": \"bar\" }", + new HashSet<>(List.of("{ \"foo\": \"bar\" }")), List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice)))); final Context context = InstrumentationRegistry.getInstrumentation().getContext(); @@ -143,7 +144,7 @@ public class CredentialManagerTest { public void testGetCredential_nullRequest() { GetCredentialRequest nullRequest = null; assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(nullRequest, mMockActivity, null, mExecutor, + () -> mCredentialManager.getCredential(mMockActivity, nullRequest, null, mExecutor, result -> { })); } @@ -151,7 +152,7 @@ public class CredentialManagerTest { @Test public void testGetCredential_nullActivity() { assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(mGetRequest, null, null, mExecutor, + () -> mCredentialManager.getCredential(null, mGetRequest, null, mExecutor, result -> { })); } @@ -159,7 +160,7 @@ public class CredentialManagerTest { @Test public void testGetCredential_nullExecutor() { assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null, + () -> mCredentialManager.getCredential(mMockActivity, mGetRequest, null, null, result -> { })); } @@ -167,7 +168,7 @@ public class CredentialManagerTest { @Test public void testGetCredential_nullCallback() { assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null, + () -> mCredentialManager.getCredential(mMockActivity, mGetRequest, null, null, null)); } @@ -183,7 +184,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback); + mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); callbackCaptor.getValue().onError(GetCredentialException.TYPE_NO_CREDENTIAL, @@ -199,7 +200,7 @@ public class CredentialManagerTest { final CancellationSignal cancellation = new CancellationSignal(); cancellation.cancel(); - mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.getCredential(mMockActivity, mGetRequest, cancellation, mExecutor, result -> { }); @@ -217,7 +218,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeGetCredential(any(), any(), any())).thenReturn( serviceSignal); - mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.getCredential(mMockActivity, mGetRequest, cancellation, mExecutor, callback); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); @@ -240,7 +241,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback); + mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); callbackCaptor.getValue().onResponse(new GetCredentialResponse(cred)); @@ -252,7 +253,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullRequest() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(null, mMockActivity, null, mExecutor, + () -> mCredentialManager.createCredential(mMockActivity, null, null, mExecutor, result -> { })); } @@ -260,7 +261,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullActivity() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(mCreateRequest, null, null, mExecutor, + () -> mCredentialManager.createCredential(null, mCreateRequest, null, mExecutor, result -> { })); } @@ -268,7 +269,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullExecutor() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, null, + () -> mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, null, result -> { })); } @@ -276,7 +277,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullCallback() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, + () -> mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, null)); } @@ -285,7 +286,7 @@ public class CredentialManagerTest { final CancellationSignal cancellation = new CancellationSignal(); cancellation.cancel(); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, cancellation, mExecutor, result -> { }); @@ -303,7 +304,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeCreateCredential(any(), any(), any())).thenReturn( serviceSignal); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, cancellation, mExecutor, callback); verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), @@ -325,7 +326,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), eq(mPackageName)); @@ -352,7 +353,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), eq(mPackageName)); diff --git a/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java b/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java index 306ecdee9167..61e976bee35e 100644 --- a/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java +++ b/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java @@ -20,8 +20,6 @@ import static com.android.internal.util.LatencyTracker.ActionProperties.ENABLE_S import static com.android.internal.util.LatencyTracker.ActionProperties.SAMPLE_INTERVAL_SUFFIX; import static com.android.internal.util.LatencyTracker.ActionProperties.TRACE_THRESHOLD_SUFFIX; -import static com.google.common.truth.Truth.assertThat; - import android.os.ConditionVariable; import android.provider.DeviceConfig; import android.util.Log; @@ -33,7 +31,6 @@ import com.android.internal.annotations.GuardedBy; import com.google.common.collect.ImmutableMap; -import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -46,7 +43,6 @@ import java.util.concurrent.atomic.AtomicReference; public final class FakeLatencyTracker extends LatencyTracker { private static final String TAG = "FakeLatencyTracker"; - private static final Duration FORCE_UPDATE_TIMEOUT = Duration.ofSeconds(1); private final Object mLock = new Object(); @GuardedBy("mLock") @@ -203,7 +199,7 @@ public final class FakeLatencyTracker extends LatencyTracker { } } Log.i(TAG, "waiting for condition"); - assertThat(mDeviceConfigPropertiesUpdated.block(FORCE_UPDATE_TIMEOUT.toMillis())).isTrue(); + mDeviceConfigPropertiesUpdated.block(); } public void waitForMatchingActionProperties(ActionProperties actionProperties) @@ -232,7 +228,7 @@ public final class FakeLatencyTracker extends LatencyTracker { } } Log.i(TAG, "waiting for condition"); - assertThat(mDeviceConfigPropertiesUpdated.block(FORCE_UPDATE_TIMEOUT.toMillis())).isTrue(); + mDeviceConfigPropertiesUpdated.block(); } public void waitForActionEnabledState(int action, boolean enabledState) throws Exception { @@ -260,7 +256,7 @@ public final class FakeLatencyTracker extends LatencyTracker { } } Log.i(TAG, "waiting for condition"); - assertThat(mDeviceConfigPropertiesUpdated.block(FORCE_UPDATE_TIMEOUT.toMillis())).isTrue(); + mDeviceConfigPropertiesUpdated.block(); } public void waitForGlobalEnabledState(boolean enabledState) throws Exception { @@ -280,6 +276,6 @@ public final class FakeLatencyTracker extends LatencyTracker { } } Log.i(TAG, "waiting for condition"); - assertThat(mDeviceConfigPropertiesUpdated.block(FORCE_UPDATE_TIMEOUT.toMillis())).isTrue(); + mDeviceConfigPropertiesUpdated.block(); } } diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index 247d484d77ea..e27cd978e6be 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -424,6 +424,10 @@ key 580 APP_SWITCH key 582 VOICE_ASSIST # Linux KEY_ASSISTANT key 583 ASSIST +key 656 MACRO_1 +key 657 MACRO_2 +key 658 MACRO_3 +key 659 MACRO_4 # Keys defined by HID usages key usage 0x0c0067 WINDOW diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 60898ef80a7e..0b29973507d2 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -38,8 +38,11 @@ import android.graphics.drawable.AnimatedImageDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.NinePatchDrawable; +import android.media.MediaCodecInfo; +import android.media.MediaCodecList; import android.net.Uri; import android.os.Build; +import android.os.SystemProperties; import android.os.Trace; import android.system.ErrnoException; import android.system.Os; @@ -914,7 +917,6 @@ public final class ImageDecoder implements AutoCloseable { case "image/gif": case "image/heif": case "image/heic": - case "image/avif": case "image/bmp": case "image/x-ico": case "image/vnd.wap.wbmp": @@ -929,6 +931,8 @@ public final class ImageDecoder implements AutoCloseable { case "image/x-pentax-pef": case "image/x-samsung-srw": return true; + case "image/avif": + return isP010SupportedForAV1(); default: return false; } @@ -2064,6 +2068,53 @@ public final class ImageDecoder implements AutoCloseable { return decodeBitmapImpl(src, null); } + private static boolean sIsP010SupportedForAV1 = false; + private static boolean sIsP010SupportedForAV1Initialized = false; + private static final Object sIsP010SupportedForAV1Lock = new Object(); + + /** + * Checks if the device supports decoding 10-bit AV1. + */ + @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API. + private static boolean isP010SupportedForAV1() { + synchronized (sIsP010SupportedForAV1Lock) { + if (sIsP010SupportedForAV1Initialized) { + return sIsP010SupportedForAV1; + } + + sIsP010SupportedForAV1Initialized = true; + + if (hasHardwareDecoder("video/av01")) { + sIsP010SupportedForAV1 = true; + return true; + } + + sIsP010SupportedForAV1 = Build.VERSION.DEVICE_INITIAL_SDK_INT + >= Build.VERSION_CODES.S; + return sIsP010SupportedForAV1; + } + } + + /** + * Checks if the device has hardware decoder for the target mime type. + */ + private static boolean hasHardwareDecoder(String mime) { + final MediaCodecList sMCL = new MediaCodecList(MediaCodecList.REGULAR_CODECS); + for (MediaCodecInfo info : sMCL.getCodecInfos()) { + if (info.isEncoder() == false && info.isHardwareAccelerated()) { + try { + if (info.getCapabilitiesForType(mime) != null) { + return true; + } + } catch (IllegalArgumentException e) { + // mime is not supported + return false; + } + } + } + return false; + } + /** * Private method called by JNI. */ diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 404429ad41d3..89f4890c254e 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -40,7 +40,9 @@ import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceh import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent; import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked; import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPAND_FAILED_NO_TF_INFO; +import static androidx.window.extensions.embedding.SplitPresenter.getActivitiesMinDimensionsPair; import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair; +import static androidx.window.extensions.embedding.SplitPresenter.getTaskWindowMetrics; import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit; import android.app.Activity; @@ -1037,9 +1039,15 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen final TaskFragmentContainer primaryContainer = getContainerWithActivity( primaryActivity); final SplitContainer splitContainer = getActiveSplitForContainer(primaryContainer); - final WindowMetrics taskWindowMetrics = mPresenter.getTaskWindowMetrics(primaryActivity); + final TaskContainer.TaskProperties taskProperties = mPresenter + .getTaskProperties(primaryActivity); + final SplitAttributes calculatedSplitAttributes = mPresenter.computeSplitAttributes( + taskProperties, splitRule, splitRule.getDefaultSplitAttributes(), + getActivitiesMinDimensionsPair(primaryActivity, secondaryActivity)); if (splitContainer != null && primaryContainer == splitContainer.getPrimaryContainer() - && canReuseContainer(splitRule, splitContainer.getSplitRule(), taskWindowMetrics)) { + && canReuseContainer(splitRule, splitContainer.getSplitRule(), + getTaskWindowMetrics(taskProperties.getConfiguration()), + calculatedSplitAttributes, splitContainer.getCurrentSplitAttributes())) { // Can launch in the existing secondary container if the rules share the same // presentation. final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer(); @@ -1058,7 +1066,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } } // Create new split pair. - mPresenter.createNewSplitContainer(wct, primaryActivity, secondaryActivity, splitRule); + mPresenter.createNewSplitContainer(wct, primaryActivity, secondaryActivity, splitRule, + calculatedSplitAttributes); return true; } @@ -1283,9 +1292,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } final TaskFragmentContainer existingContainer = getContainerWithActivity(primaryActivity); final SplitContainer splitContainer = getActiveSplitForContainer(existingContainer); - final WindowMetrics taskWindowMetrics = mPresenter.getTaskWindowMetrics(primaryActivity); + final TaskContainer.TaskProperties taskProperties = mPresenter + .getTaskProperties(primaryActivity); + final WindowMetrics taskWindowMetrics = getTaskWindowMetrics( + taskProperties.getConfiguration()); + final SplitAttributes calculatedSplitAttributes = mPresenter.computeSplitAttributes( + taskProperties, splitRule, splitRule.getDefaultSplitAttributes(), + getActivityIntentMinDimensionsPair(primaryActivity, intent)); if (splitContainer != null && existingContainer == splitContainer.getPrimaryContainer() - && (canReuseContainer(splitRule, splitContainer.getSplitRule(), taskWindowMetrics) + && (canReuseContainer(splitRule, splitContainer.getSplitRule(), taskWindowMetrics, + calculatedSplitAttributes, splitContainer.getCurrentSplitAttributes()) // TODO(b/231845476) we should always respect clearTop. || !respectClearTop) && mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity, @@ -1296,7 +1312,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } // Create a new TaskFragment to split with the primary activity for the new activity. return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, intent, - splitRule); + splitRule, calculatedSplitAttributes); } /** @@ -2273,21 +2289,29 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } /** - * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if - * there is any. + * If the two rules have the same presentation, and the calculated {@link SplitAttributes} + * matches the {@link SplitAttributes} of {@link SplitContainer}, we can reuse the same + * {@link SplitContainer} if there is any. */ private static boolean canReuseContainer(@NonNull SplitRule rule1, @NonNull SplitRule rule2, - @NonNull WindowMetrics parentWindowMetrics) { + @NonNull WindowMetrics parentWindowMetrics, + @NonNull SplitAttributes calculatedSplitAttributes, + @NonNull SplitAttributes containerSplitAttributes) { if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) { return false; } - return haveSamePresentation((SplitPairRule) rule1, (SplitPairRule) rule2, - parentWindowMetrics); + return areRulesSamePresentation((SplitPairRule) rule1, (SplitPairRule) rule2, + parentWindowMetrics) + // Besides rules, we should also check whether the SplitContainer's splitAttributes + // matches the current splitAttributes or not. The splitAttributes may change + // if the app chooses different SplitAttributes calculator function before a new + // activity is started even they match the same splitRule. + && calculatedSplitAttributes.equals(containerSplitAttributes); } /** Whether the two rules have the same presentation. */ @VisibleForTesting - static boolean haveSamePresentation(@NonNull SplitPairRule rule1, + static boolean areRulesSamePresentation(@NonNull SplitPairRule rule1, @NonNull SplitPairRule rule2, @NonNull WindowMetrics parentWindowMetrics) { if (rule1.getTag() != null || rule2.getTag() != null) { // Tag must be unique if it is set. We don't want to reuse the container if the rules diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index 040851181e92..53d39d9fa28e 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -174,12 +174,9 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull TaskFragmentContainer createNewSplitWithEmptySideContainer( @NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity, - @NonNull Intent secondaryIntent, @NonNull SplitPairRule rule) { + @NonNull Intent secondaryIntent, @NonNull SplitPairRule rule, + @NonNull SplitAttributes splitAttributes) { final TaskProperties taskProperties = getTaskProperties(primaryActivity); - final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair( - primaryActivity, secondaryIntent); - final SplitAttributes splitAttributes = computeSplitAttributes(taskProperties, rule, - rule.getDefaultSplitAttributes(), minDimensionsPair); final Rect primaryRelBounds = getRelBoundsForPosition(POSITION_START, taskProperties, splitAttributes); final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct, @@ -217,15 +214,12 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { * same container as the primary activity, a new container will be * created and the activity will be re-parented to it. * @param rule The split rule to be applied to the container. + * @param splitAttributes The {@link SplitAttributes} to apply */ void createNewSplitContainer(@NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity, - @NonNull SplitPairRule rule) { + @NonNull SplitPairRule rule, @NonNull SplitAttributes splitAttributes) { final TaskProperties taskProperties = getTaskProperties(primaryActivity); - final Pair<Size, Size> minDimensionsPair = getActivitiesMinDimensionsPair(primaryActivity, - secondaryActivity); - final SplitAttributes splitAttributes = computeSplitAttributes(taskProperties, rule, - rule.getDefaultSplitAttributes(), minDimensionsPair); final Rect primaryRelBounds = getRelBoundsForPosition(POSITION_START, taskProperties, splitAttributes); final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct, @@ -654,7 +648,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { } @NonNull - private static Pair<Size, Size> getActivitiesMinDimensionsPair( + static Pair<Size, Size> getActivitiesMinDimensionsPair( @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity) { return new Pair<>(getMinDimensions(primaryActivity), getMinDimensions(secondaryActivity)); } @@ -716,24 +710,16 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull SplitAttributes splitAttributes) { final Configuration taskConfiguration = taskProperties.getConfiguration(); final FoldingFeature foldingFeature = getFoldingFeature(taskProperties); - final SplitType splitType = computeSplitType(splitAttributes, taskConfiguration, - foldingFeature); - final SplitAttributes computedSplitAttributes = new SplitAttributes.Builder() - .setSplitType(splitType) - .setLayoutDirection(splitAttributes.getLayoutDirection()) - .build(); - if (!shouldShowSplit(computedSplitAttributes)) { + if (!shouldShowSplit(splitAttributes)) { return new Rect(); } final Rect bounds; switch (position) { case POSITION_START: - bounds = getPrimaryBounds(taskConfiguration, computedSplitAttributes, - foldingFeature); + bounds = getPrimaryBounds(taskConfiguration, splitAttributes, foldingFeature); break; case POSITION_END: - bounds = getSecondaryBounds(taskConfiguration, computedSplitAttributes, - foldingFeature); + bounds = getSecondaryBounds(taskConfiguration, splitAttributes, foldingFeature); break; case POSITION_FILL: default: @@ -748,63 +734,76 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull private Rect getPrimaryBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { - if (!shouldShowSplit(splitAttributes)) { + final SplitAttributes computedSplitAttributes = updateSplitAttributesType(splitAttributes, + computeSplitType(splitAttributes, taskConfiguration, foldingFeature)); + if (!shouldShowSplit(computedSplitAttributes)) { return new Rect(); } - switch (splitAttributes.getLayoutDirection()) { + switch (computedSplitAttributes.getLayoutDirection()) { case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT: { - return getLeftContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getLeftContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT: { - return getRightContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getRightContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } case SplitAttributes.LayoutDirection.LOCALE: { final boolean isLtr = taskConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; return isLtr - ? getLeftContainerBounds(taskConfiguration, splitAttributes, foldingFeature) - : getRightContainerBounds(taskConfiguration, splitAttributes, + ? getLeftContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature) + : getRightContainerBounds(taskConfiguration, computedSplitAttributes, foldingFeature); } case SplitAttributes.LayoutDirection.TOP_TO_BOTTOM: { - return getTopContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getTopContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } case SplitAttributes.LayoutDirection.BOTTOM_TO_TOP: { - return getBottomContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getBottomContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } default: throw new IllegalArgumentException("Unknown layout direction:" - + splitAttributes.getLayoutDirection()); + + computedSplitAttributes.getLayoutDirection()); } } @NonNull private Rect getSecondaryBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { - if (!shouldShowSplit(splitAttributes)) { + final SplitAttributes computedSplitAttributes = updateSplitAttributesType(splitAttributes, + computeSplitType(splitAttributes, taskConfiguration, foldingFeature)); + if (!shouldShowSplit(computedSplitAttributes)) { return new Rect(); } - switch (splitAttributes.getLayoutDirection()) { + switch (computedSplitAttributes.getLayoutDirection()) { case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT: { - return getRightContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getRightContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT: { - return getLeftContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getLeftContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } case SplitAttributes.LayoutDirection.LOCALE: { final boolean isLtr = taskConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; return isLtr - ? getRightContainerBounds(taskConfiguration, splitAttributes, + ? getRightContainerBounds(taskConfiguration, computedSplitAttributes, foldingFeature) - : getLeftContainerBounds(taskConfiguration, splitAttributes, + : getLeftContainerBounds(taskConfiguration, computedSplitAttributes, foldingFeature); } case SplitAttributes.LayoutDirection.TOP_TO_BOTTOM: { - return getBottomContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getBottomContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } case SplitAttributes.LayoutDirection.BOTTOM_TO_TOP: { - return getTopContainerBounds(taskConfiguration, splitAttributes, foldingFeature); + return getTopContainerBounds(taskConfiguration, computedSplitAttributes, + foldingFeature); } default: throw new IllegalArgumentException("Unknown layout direction:" @@ -812,6 +811,19 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { } } + /** + * Returns the {@link SplitAttributes} that update the {@link SplitType} to + * {@code splitTypeToUpdate}. + */ + private static SplitAttributes updateSplitAttributesType( + @NonNull SplitAttributes splitAttributes, @NonNull SplitType splitTypeToUpdate) { + return new SplitAttributes.Builder() + .setSplitType(splitTypeToUpdate) + .setLayoutDirection(splitAttributes.getLayoutDirection()) + .setAnimationBackgroundColor(splitAttributes.getAnimationBackgroundColor()) + .build(); + } + @NonNull private Rect getLeftContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { @@ -904,7 +916,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { } @Nullable - private FoldingFeature getFoldingFeature(@NonNull TaskProperties taskProperties) { + @VisibleForTesting + FoldingFeature getFoldingFeature(@NonNull TaskProperties taskProperties) { final int displayId = taskProperties.getDisplayId(); final WindowConfiguration windowConfiguration = taskProperties.getConfiguration() .windowConfiguration; @@ -1027,7 +1040,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { } @NonNull - private static WindowMetrics getTaskWindowMetrics(@NonNull Configuration taskConfiguration) { + static WindowMetrics getTaskWindowMetrics(@NonNull Configuration taskConfiguration) { final Rect taskBounds = taskConfiguration.windowConfiguration.getBounds(); // TODO(b/190433398): Supply correct insets. final float density = taskConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java index cbdc262c0594..ff08782e8cd8 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java @@ -565,7 +565,6 @@ public class SplitControllerTest { assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer, container)); assertTrue(primaryContainer.areLastRequestedBoundsEqual(null)); assertTrue(container.areLastRequestedBoundsEqual(null)); - assertEquals(container, mSplitController.getContainerWithActivity(secondaryActivity)); } @Test @@ -1008,9 +1007,8 @@ public class SplitControllerTest { assertTrue(result); assertSplitPair(primaryActivity, mActivity, true /* matchParentBounds */); - assertEquals(mSplitController.getContainerWithActivity(secondaryActivity), - mSplitController.getContainerWithActivity(mActivity)); - verify(mSplitPresenter, never()).createNewSplitContainer(any(), any(), any(), any()); + assertTrue(mSplitController.getContainerWithActivity(mActivity) + .areLastRequestedBoundsEqual(new Rect())); } @Test @@ -1215,7 +1213,7 @@ public class SplitControllerTest { .build(); assertTrue("Rules must have same presentation if tags are null and has same properties.", - SplitController.haveSamePresentation(splitRule1, splitRule2, + SplitController.areRulesSamePresentation(splitRule1, splitRule2, new WindowMetrics(TASK_BOUNDS, WindowInsets.CONSUMED))); splitRule2 = createSplitPairRuleBuilder( @@ -1230,7 +1228,7 @@ public class SplitControllerTest { assertFalse("Rules must have different presentations if tags are not equal regardless" + "of other properties", - SplitController.haveSamePresentation(splitRule1, splitRule2, + SplitController.areRulesSamePresentation(splitRule1, splitRule2, new WindowMetrics(TASK_BOUNDS, WindowInsets.CONSUMED))); } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java index 83301564d7a4..6981d9d7ebb8 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java @@ -678,7 +678,8 @@ public class SplitPresenterTest { .setShouldClearTop(false) .build(); - mPresenter.createNewSplitContainer(mTransaction, mActivity, secondaryActivity, rule); + mPresenter.createNewSplitContainer(mTransaction, mActivity, secondaryActivity, rule, + SPLIT_ATTRIBUTES); assertEquals(primaryTf, mController.getContainerWithActivity(mActivity)); final TaskFragmentContainer secondaryTf = mController.getContainerWithActivity( @@ -729,6 +730,27 @@ public class SplitPresenterTest { } @Test + public void testComputeSplitAttributesOnHingeSplitTypeOnDeviceWithoutFoldingFeature() { + final SplitAttributes hingeSplitAttrs = new SplitAttributes.Builder() + .setSplitType(new SplitAttributes.SplitType.HingeSplitType( + SplitAttributes.SplitType.RatioSplitType.splitEqually())) + .build(); + final SplitPairRule splitPairRule = createSplitPairRuleBuilder( + activityPair -> true, + activityIntentPair -> true, + windowMetrics -> windowMetrics.getBounds().equals(TASK_BOUNDS)) + .setFinishSecondaryWithPrimary(DEFAULT_FINISH_SECONDARY_WITH_PRIMARY) + .setFinishPrimaryWithSecondary(DEFAULT_FINISH_PRIMARY_WITH_SECONDARY) + .setDefaultSplitAttributes(hingeSplitAttrs) + .build(); + final TaskContainer.TaskProperties taskProperties = getTaskProperties(); + doReturn(null).when(mPresenter).getFoldingFeature(any()); + + assertEquals(hingeSplitAttrs, mPresenter.computeSplitAttributes(taskProperties, + splitPairRule, hingeSplitAttrs, null /* minDimensionsPair */)); + } + + @Test public void testGetTaskWindowMetrics() { final Configuration taskConfig = new Configuration(); taskConfig.windowConfiguration.setBounds(TASK_BOUNDS); diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index c7c94246b96a..54978bd4496d 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -46,6 +46,8 @@ filegroup { "src/com/android/wm/shell/common/split/SplitScreenConstants.java", "src/com/android/wm/shell/sysui/ShellSharedConstants.java", "src/com/android/wm/shell/common/TransactionPool.java", + "src/com/android/wm/shell/common/bubbles/*.java", + "src/com/android/wm/shell/common/TriangleShape.java", "src/com/android/wm/shell/animation/Interpolators.java", "src/com/android/wm/shell/pip/PipContentOverlay.java", "src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java", diff --git a/libs/WindowManager/Shell/res/drawable/caption_desktop_button.xml b/libs/WindowManager/Shell/res/drawable/caption_desktop_button.xml deleted file mode 100644 index 8779cc09715b..000000000000 --- a/libs/WindowManager/Shell/res/drawable/caption_desktop_button.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group android:scaleX="0.5" - android:scaleY="0.5" - android:translateX="6.0" - android:translateY="6.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M5.958,37.708Q4.458,37.708 3.354,36.604Q2.25,35.5 2.25,34V18.292Q2.25,16.792 3.354,15.688Q4.458,14.583 5.958,14.583H9.5V5.958Q9.5,4.458 10.625,3.354Q11.75,2.25 13.208,2.25H34Q35.542,2.25 36.646,3.354Q37.75,4.458 37.75,5.958V21.667Q37.75,23.167 36.646,24.271Q35.542,25.375 34,25.375H30.5V34Q30.5,35.5 29.396,36.604Q28.292,37.708 26.792,37.708ZM5.958,34H26.792Q26.792,34 26.792,34Q26.792,34 26.792,34V21.542H5.958V34Q5.958,34 5.958,34Q5.958,34 5.958,34ZM30.5,21.667H34Q34,21.667 34,21.667Q34,21.667 34,21.667V9.208H13.208V14.583H26.833Q28.375,14.583 29.438,15.667Q30.5,16.75 30.5,18.25Z"/> - </group> -</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_floating_button.xml b/libs/WindowManager/Shell/res/drawable/caption_floating_button.xml deleted file mode 100644 index ea0fbb0e5d33..000000000000 --- a/libs/WindowManager/Shell/res/drawable/caption_floating_button.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group android:scaleX="0.5" - android:scaleY="0.5" - android:translateX="6.0" - android:translateY="6.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M18.167,21.875H29.833V10.208H18.167ZM7.875,35.833Q6.375,35.833 5.271,34.729Q4.167,33.625 4.167,32.125V7.875Q4.167,6.375 5.271,5.271Q6.375,4.167 7.875,4.167H32.125Q33.625,4.167 34.729,5.271Q35.833,6.375 35.833,7.875V32.125Q35.833,33.625 34.729,34.729Q33.625,35.833 32.125,35.833ZM7.875,32.125H32.125Q32.125,32.125 32.125,32.125Q32.125,32.125 32.125,32.125V7.875Q32.125,7.875 32.125,7.875Q32.125,7.875 32.125,7.875H7.875Q7.875,7.875 7.875,7.875Q7.875,7.875 7.875,7.875V32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125ZM7.875,7.875Q7.875,7.875 7.875,7.875Q7.875,7.875 7.875,7.875V32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125V7.875Q7.875,7.875 7.875,7.875Q7.875,7.875 7.875,7.875Z"/> - </group> -</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_fullscreen_button.xml b/libs/WindowManager/Shell/res/drawable/caption_fullscreen_button.xml deleted file mode 100644 index c55cbe2d054c..000000000000 --- a/libs/WindowManager/Shell/res/drawable/caption_fullscreen_button.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group android:scaleX="0.5" - android:scaleY="0.5" - android:translateX="6.0" - android:translateY="6.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M34.042,14.625V9.333Q34.042,9.333 34.042,9.333Q34.042,9.333 34.042,9.333H28.708V5.708H33.917Q35.458,5.708 36.562,6.833Q37.667,7.958 37.667,9.458V14.625ZM2.375,14.625V9.458Q2.375,7.958 3.479,6.833Q4.583,5.708 6.125,5.708H11.292V9.333H6Q6,9.333 6,9.333Q6,9.333 6,9.333V14.625ZM28.708,34.25V30.667H34.042Q34.042,30.667 34.042,30.667Q34.042,30.667 34.042,30.667V25.333H37.667V30.542Q37.667,32 36.562,33.125Q35.458,34.25 33.917,34.25ZM6.125,34.25Q4.583,34.25 3.479,33.125Q2.375,32 2.375,30.542V25.333H6V30.667Q6,30.667 6,30.667Q6,30.667 6,30.667H11.292V34.25ZM9.333,27.292V12.667H30.708V27.292ZM12.917,23.708H27.125V16.25H12.917ZM12.917,23.708V16.25V23.708Z"/> - </group> -</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_more_button.xml b/libs/WindowManager/Shell/res/drawable/caption_more_button.xml deleted file mode 100644 index 447df43dfddd..000000000000 --- a/libs/WindowManager/Shell/res/drawable/caption_more_button.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group android:scaleX="0.5" - android:scaleY="0.5" - android:translateX="6.0" - android:translateY="6.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M8.083,22.833Q6.917,22.833 6.104,22Q5.292,21.167 5.292,20Q5.292,18.833 6.125,18Q6.958,17.167 8.125,17.167Q9.292,17.167 10.125,18Q10.958,18.833 10.958,20Q10.958,21.167 10.125,22Q9.292,22.833 8.083,22.833ZM20,22.833Q18.833,22.833 18,22Q17.167,21.167 17.167,20Q17.167,18.833 18,18Q18.833,17.167 20,17.167Q21.167,17.167 22,18Q22.833,18.833 22.833,20Q22.833,21.167 22,22Q21.167,22.833 20,22.833ZM31.875,22.833Q30.708,22.833 29.875,22Q29.042,21.167 29.042,20Q29.042,18.833 29.875,18Q30.708,17.167 31.917,17.167Q33.083,17.167 33.896,18Q34.708,18.833 34.708,20Q34.708,21.167 33.875,22Q33.042,22.833 31.875,22.833Z"/> - </group> -</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_select_button.xml b/libs/WindowManager/Shell/res/drawable/caption_select_button.xml deleted file mode 100644 index 8c60c8407174..000000000000 --- a/libs/WindowManager/Shell/res/drawable/caption_select_button.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2023 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group - android:translateX="4.0" - android:translateY="6.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M13.7021 12.5833L16.5676 15.5L15.426 16.7333L12.526 13.8333L10.4426 15.9167V10.5H15.9176L13.7021 12.5833ZM13.8343 3.83333H15.501V5.5H13.8343V3.83333ZM15.501 2.16667H13.8343V0.566667C14.751 0.566667 15.501 1.33333 15.501 2.16667ZM10.501 0.5H12.1676V2.16667H10.501V0.5ZM13.8343 7.16667H15.501V8.83333H13.8343V7.16667ZM5.50098 15.5H3.83431V13.8333H5.50098V15.5ZM2.16764 5.5H0.500977V3.83333H2.16764V5.5ZM2.16764 0.566667V2.16667H0.500977C0.500977 1.33333 1.33431 0.566667 2.16764 0.566667ZM2.16764 12.1667H0.500977V10.5H2.16764V12.1667ZM5.50098 2.16667H3.83431V0.5H5.50098V2.16667ZM8.83431 2.16667H7.16764V0.5H8.83431V2.16667ZM8.83431 15.5H7.16764V13.8333H8.83431V15.5ZM2.16764 8.83333H0.500977V7.16667H2.16764V8.83333ZM2.16764 15.5667C1.25098 15.5667 0.500977 14.6667 0.500977 13.8333H2.16764V15.5667Z"/> - </group> -</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_split_screen_button.xml b/libs/WindowManager/Shell/res/drawable/caption_split_screen_button.xml deleted file mode 100644 index c334a543a86a..000000000000 --- a/libs/WindowManager/Shell/res/drawable/caption_split_screen_button.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group android:translateX="6.0" - android:translateY="8.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M18 14L13 14L13 2L18 2L18 14ZM20 14L20 2C20 0.9 19.1 -3.93402e-08 18 -8.74228e-08L13 -3.0598e-07C11.9 -3.54062e-07 11 0.9 11 2L11 14C11 15.1 11.9 16 13 16L18 16C19.1 16 20 15.1 20 14ZM7 14L2 14L2 2L7 2L7 14ZM9 14L9 2C9 0.9 8.1 -5.20166e-07 7 -5.68248e-07L2 -7.86805e-07C0.9 -8.34888e-07 -3.93403e-08 0.9 -8.74228e-08 2L-6.11959e-07 14C-6.60042e-07 15.1 0.9 16 2 16L7 16C8.1 16 9 15.1 9 14Z"/> </group> -</vector> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml index c6e634c6622c..4ee10f429b37 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml @@ -17,6 +17,5 @@ <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/white" /> - <corners android:radius="@dimen/caption_menu_corner_radius" /> - <stroke android:width="1dp" android:color="#b3b3b3"/> + <corners android:radius="@dimen/desktop_mode_handle_menu_corner_radius" /> </shape> diff --git a/libs/WindowManager/Shell/res/drawable/caption_collapse_menu_button.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_close.xml index 166552dcb9e8..b7521d4200c0 100644 --- a/libs/WindowManager/Shell/res/drawable/caption_collapse_menu_button.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_close.xml @@ -15,16 +15,12 @@ ~ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24.0dp" - android:height="24.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0" -> - <group android:scaleX="1.25" - android:scaleY="1.75" - android:translateY="6.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M10.3937 6.93935L11.3337 5.99935L6.00033 0.666016L0.666992 5.99935L1.60699 6.93935L6.00033 2.55268"/> - </group> + android:height="20dp" + android:tint="#000000" + android:viewportHeight="24" + android:viewportWidth="24" + android:width="20dp"> + <path + android:fillColor="@android:color/white" + android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> </vector> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_desktop.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_desktop.xml new file mode 100644 index 000000000000..e2b724b8abfd --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_desktop.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M16.667,15H3.333V5H16.667V15ZM16.667,16.667C17.583,16.667 18.333,15.917 18.333,15V5C18.333,4.083 17.583,3.333 16.667,3.333H3.333C2.417,3.333 1.667,4.083 1.667,5V15C1.667,15.917 2.417,16.667 3.333,16.667H16.667ZM15,6.667H9.167V8.333H13.333V10H15V6.667ZM5,9.167H12.5V13.333H5V9.167Z" + android:fillColor="#1C1C14" + android:fillType="evenOdd"/> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_close_button.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_floating.xml index e258564c70f7..b0ea98e5f788 100644 --- a/libs/WindowManager/Shell/res/drawable/caption_close_button.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_floating.xml @@ -15,16 +15,12 @@ ~ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group android:scaleX="0.5" - android:scaleY="0.5" - android:translateY="4.0"> - <path - android:fillColor="#FFFF0000" - android:pathData="M12.45,38.35 L9.65,35.55 21.2,24 9.65,12.45 12.45,9.65 24,21.2 35.55,9.65 38.35,12.45 26.8,24 38.35,35.55 35.55,38.35 24,26.8Z"/> - </group> + android:width="21dp" + android:height="20dp" + android:viewportWidth="21" + android:viewportHeight="20"> + <path + android:pathData="M3.667,15H17V5H3.667V15ZM18.667,15C18.667,15.917 17.917,16.667 17,16.667H3.667C2.75,16.667 2,15.917 2,15V5C2,4.083 2.75,3.333 3.667,3.333H17C17.917,3.333 18.667,4.083 18.667,5V15ZM11.167,6.667H15.333V11.667H11.167V6.667Z" + android:fillColor="#1C1C14" + android:fillType="evenOdd"/> </vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_screenshot_button.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_fullscreen.xml index 7c86888f5226..99e1d268c97c 100644 --- a/libs/WindowManager/Shell/res/drawable/caption_screenshot_button.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_fullscreen.xml @@ -15,16 +15,12 @@ ~ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="32.0" - android:viewportHeight="32.0" -> - <group android:scaleX="0.5" - android:scaleY="0.5" - android:translateY="4.0"> - <path - android:fillColor="@android:color/black" - android:pathData="M10,38V28.35H13V35H19.65V38ZM10,19.65V10H19.65V13H13V19.65ZM28.35,38V35H35V28.35H38V38ZM35,19.65V13H28.35V10H38V19.65Z"/> - </group> + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M3.333,15H16.667V5H3.333V15ZM18.333,15C18.333,15.917 17.583,16.667 16.667,16.667H3.333C2.417,16.667 1.667,15.917 1.667,15V5C1.667,4.083 2.417,3.333 3.333,3.333H16.667C17.583,3.333 18.333,4.083 18.333,5V15ZM5,6.667H15V13.333H5V6.667Z" + android:fillColor="#1C1C14" + android:fillType="evenOdd"/> </vector> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_screenshot.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_screenshot.xml new file mode 100644 index 000000000000..79a91250bb78 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_screenshot.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M18.333,5.833L18.333,8.333L16.667,8.333L16.667,5.833L13.333,5.833L13.333,4.167L16.667,4.167C17.587,4.167 18.333,4.913 18.333,5.833Z" + android:fillColor="#1C1C14"/> + <path + android:pathData="M6.667,4.167L3.333,4.167C2.413,4.167 1.667,4.913 1.667,5.833L1.667,8.333L3.333,8.333L3.333,5.833L6.667,5.833L6.667,4.167Z" + android:fillColor="#1C1C14"/> + <path + android:pathData="M6.667,14.167L3.333,14.167L3.333,11.667L1.667,11.667L1.667,14.167C1.667,15.087 2.413,15.833 3.333,15.833L6.667,15.833L6.667,14.167Z" + android:fillColor="#1C1C14"/> + <path + android:pathData="M13.333,15.833L16.667,15.833C17.587,15.833 18.333,15.087 18.333,14.167L18.333,11.667L16.667,11.667L16.667,14.167L13.333,14.167L13.333,15.833Z" + android:fillColor="#1C1C14"/> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_select.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_select.xml new file mode 100644 index 000000000000..7c4f49979455 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_select.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M15.701,14.583L18.567,17.5L17.425,18.733L14.525,15.833L12.442,17.917V12.5H17.917L15.701,14.583ZM15.833,5.833H17.5V7.5H15.833V5.833ZM17.5,4.167H15.833V2.567C16.75,2.567 17.5,3.333 17.5,4.167ZM12.5,2.5H14.167V4.167H12.5V2.5ZM15.833,9.167H17.5V10.833H15.833V9.167ZM7.5,17.5H5.833V15.833H7.5V17.5ZM4.167,7.5H2.5V5.833H4.167V7.5ZM4.167,2.567V4.167H2.5C2.5,3.333 3.333,2.567 4.167,2.567ZM4.167,14.167H2.5V12.5H4.167V14.167ZM7.5,4.167H5.833V2.5H7.5V4.167ZM10.833,4.167H9.167V2.5H10.833V4.167ZM10.833,17.5H9.167V15.833H10.833V17.5ZM4.167,10.833H2.5V9.167H4.167V10.833ZM4.167,17.567C3.25,17.567 2.5,16.667 2.5,15.833H4.167V17.567Z" + android:fillColor="#1C1C14"/> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_splitscreen.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_splitscreen.xml new file mode 100644 index 000000000000..853ab60e046f --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_splitscreen.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="21dp" + android:height="20dp" + android:viewportWidth="21" + android:viewportHeight="20"> + <path + android:pathData="M17.333,15H4V5H17.333V15ZM17.333,16.667C18.25,16.667 19,15.917 19,15V5C19,4.083 18.25,3.333 17.333,3.333H4C3.083,3.333 2.333,4.083 2.333,5V15C2.333,15.917 3.083,16.667 4,16.667H17.333ZM9.833,6.667H5.667V13.333H9.833V6.667ZM11.5,6.667H15.667V13.333H11.5V6.667Z" + android:fillColor="#1C1C14" + android:fillType="evenOdd"/> +</vector> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml index 35562b650994..f6b21bad63f4 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml @@ -61,7 +61,7 @@ android:layout_width="32dp" android:layout_height="32dp" android:padding="4dp" - android:contentDescription="@string/collapse_menu_text" + android:contentDescription="@string/expand_menu_text" android:src="@drawable/ic_baseline_expand_more_24" android:tint="@color/desktop_mode_caption_expand_button_dark" android:background="@null" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml deleted file mode 100644 index ac13eaeda6f5..000000000000 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml +++ /dev/null @@ -1,136 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<com.android.wm.shell.windowdecor.WindowDecorLinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/handle_menu" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:background="@drawable/desktop_mode_decor_menu_background" - android:divider="?android:attr/dividerHorizontal" - android:showDividers="middle" - android:dividerPadding="18dip"> - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content"> - <ImageView - android:id="@+id/application_icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_margin="12dp" - android:contentDescription="@string/app_icon_text" - android:layout_alignParentStart="true" - android:layout_centerVertical="true"/> - <TextView - android:id="@+id/application_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toEndOf="@+id/application_icon" - android:layout_toStartOf="@+id/collapse_menu_button" - android:textColor="#FF000000" - android:layout_centerVertical="true"/> - <Button - android:id="@+id/collapse_menu_button" - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginEnd="10dp" - android:contentDescription="@string/collapse_menu_text" - android:layout_alignParentEnd="true" - android:background="@drawable/ic_baseline_expand_more_24" - android:layout_centerVertical="true"/> - </RelativeLayout> - <LinearLayout - android:id="@+id/windowing_mode_buttons" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center_horizontal"> - <Space - android:layout_width="0dp" - android:layout_height="1dp" - android:layout_weight="0.5" /> - <ImageButton - style="@style/CaptionWindowingButtonStyle" - android:id="@+id/fullscreen_button" - android:contentDescription="@string/fullscreen_text" - android:src="@drawable/caption_fullscreen_button" - android:scaleType="fitCenter" - android:background="?android:selectableItemBackgroundBorderless"/> - <Space - android:layout_width="0dp" - android:layout_height="1dp" - android:layout_weight="1" /> - <ImageButton - style="@style/CaptionWindowingButtonStyle" - android:id="@+id/split_screen_button" - android:contentDescription="@string/split_screen_text" - android:src="@drawable/caption_split_screen_button" - android:scaleType="fitCenter" - android:background="?android:selectableItemBackgroundBorderless"/> - <Space - android:layout_width="0dp" - android:layout_height="1dp" - android:layout_weight="1" /> - <ImageButton - style="@style/CaptionWindowingButtonStyle" - android:id="@+id/floating_button" - android:contentDescription="@string/float_button_text" - android:src="@drawable/caption_floating_button" - android:scaleType="fitCenter" - android:background="?android:selectableItemBackgroundBorderless"/> - <Space - android:layout_width="0dp" - android:layout_height="1dp" - android:layout_weight="1" /> - <ImageButton - style="@style/CaptionWindowingButtonStyle" - android:id="@+id/desktop_button" - android:contentDescription="@string/desktop_text" - android:src="@drawable/caption_desktop_button" - android:scaleType="fitCenter" - android:background="?android:selectableItemBackgroundBorderless"/> - <Space - android:layout_width="0dp" - android:layout_height="1dp" - android:layout_weight="0.5" /> - - </LinearLayout> - <LinearLayout - android:id="@+id/menu_buttons_misc" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - <Button - style="@style/CaptionMenuButtonStyle" - android:id="@+id/screenshot_button" - android:contentDescription="@string/screenshot_text" - android:text="@string/screenshot_text" - android:drawableStart="@drawable/caption_screenshot_button"/> - <Button - style="@style/CaptionMenuButtonStyle" - android:id="@+id/select_button" - android:contentDescription="@string/select_text" - android:text="@string/select_text" - android:drawableStart="@drawable/caption_select_button"/> - <Button - style="@style/CaptionMenuButtonStyle" - android:id="@+id/close_button" - android:contentDescription="@string/close_text" - android:text="@string/close_text" - android:drawableStart="@drawable/caption_close_button" - android:textColor="#FFFF0000"/> - </LinearLayout> -</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml index 5ab159cdf264..1d6864c152c2 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml @@ -25,8 +25,9 @@ <ImageButton android:id="@+id/caption_handle" - android:layout_width="128dp" + android:layout_width="176dp" android:layout_height="42dp" + android:paddingHorizontal="24dp" android:contentDescription="@string/handle_text" android:src="@drawable/decor_handle_dark" tools:tint="@color/desktop_mode_caption_handle_bar_dark" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml new file mode 100644 index 000000000000..167a003932d6 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="@dimen/desktop_mode_handle_menu_width" + android:layout_height="@dimen/desktop_mode_handle_menu_app_info_pill_height" + android:orientation="horizontal" + android:background="@drawable/desktop_mode_decor_menu_background" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/application_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="14dp" + android:layout_marginEnd="14dp" + android:contentDescription="@string/app_icon_text"/> + + <TextView + android:id="@+id/application_name" + android:layout_width="0dp" + android:layout_height="wrap_content" + tools:text="Gmail" + android:textColor="@color/desktop_mode_caption_menu_text_color" + android:textSize="14sp" + android:textFontWeight="500" + android:lineHeight="20dp" + android:textStyle="normal" + android:layout_weight="1"/> + + <ImageButton + android:id="@+id/collapse_menu_button" + android:layout_width="32dp" + android:layout_height="32dp" + android:padding="4dp" + android:layout_marginEnd="14dp" + android:layout_marginStart="14dp" + android:contentDescription="@string/collapse_menu_text" + android:src="@drawable/ic_baseline_expand_more_24" + android:rotation="180" + android:tint="@color/desktop_mode_caption_menu_buttons_color_inactive" + android:background="?android:selectableItemBackgroundBorderless"/> +</LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml new file mode 100644 index 000000000000..40a4b53f3e1d --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="@dimen/desktop_mode_handle_menu_width" + android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height" + android:orientation="vertical" + android:background="@drawable/desktop_mode_decor_menu_background"> + + <Button + android:id="@+id/screenshot_button" + android:contentDescription="@string/screenshot_text" + android:text="@string/screenshot_text" + android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot" + android:drawableTint="@color/desktop_mode_caption_menu_buttons_color_inactive" + style="@style/DesktopModeHandleMenuActionButton"/> + + <Button + android:id="@+id/select_button" + android:contentDescription="@string/select_text" + android:text="@string/select_text" + android:drawableStart="@drawable/desktop_mode_ic_handle_menu_select" + android:drawableTint="@color/desktop_mode_caption_menu_buttons_color_inactive" + style="@style/DesktopModeHandleMenuActionButton"/> + + <Button + android:id="@+id/close_button" + android:contentDescription="@string/close_text" + android:text="@string/close_text" + android:drawableStart="@drawable/desktop_mode_ic_handle_menu_close" + android:drawableTint="@color/desktop_mode_caption_menu_buttons_color_inactive" + style="@style/DesktopModeHandleMenuActionButton"/> + +</LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml new file mode 100644 index 000000000000..95283b9e214a --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="@dimen/desktop_mode_handle_menu_width" + android:layout_height="@dimen/desktop_mode_handle_menu_windowing_pill_height" + android:orientation="horizontal" + android:background="@drawable/desktop_mode_decor_menu_background" + android:gravity="center_vertical"> + + <ImageButton + android:id="@+id/fullscreen_button" + android:layout_marginEnd="4dp" + android:contentDescription="@string/fullscreen_text" + android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen" + android:tint="@color/desktop_mode_caption_menu_buttons_color_inactive" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + + <ImageButton + android:id="@+id/split_screen_button" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" + android:contentDescription="@string/split_screen_text" + android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen" + android:tint="@color/desktop_mode_caption_menu_buttons_color_inactive" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + + <ImageButton + android:id="@+id/floating_button" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" + android:contentDescription="@string/float_button_text" + android:src="@drawable/desktop_mode_ic_handle_menu_floating" + android:tint="@color/desktop_mode_caption_menu_buttons_color_inactive" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + + <ImageButton + android:id="@+id/desktop_button" + android:layout_marginStart="4dp" + android:contentDescription="@string/desktop_text" + android:src="@drawable/desktop_mode_ic_handle_menu_desktop" + android:tint="@color/desktop_mode_caption_menu_buttons_color_active" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + +</LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml index 5af40200d240..bd48ad2cef44 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml @@ -19,10 +19,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> <View + android:id="@+id/background_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="@dimen/pip_menu_outer_space_frame" android:background="@drawable/tv_pip_menu_background" - android:elevation="@dimen/pip_menu_elevation"/> + android:elevation="@dimen/pip_menu_elevation_no_menu"/> </FrameLayout> diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index 848f28c51f7a..40c35be9200f 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Verander grootte"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Hou vas"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Laat los"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Program sal dalk nie met verdeelde skerm werk nie."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Program steun nie verdeelde skerm nie."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Hierdie app kan net in 1 venster oopgemaak word."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Program sal dalk nie op \'n sekondêre skerm werk nie."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Program steun nie begin op sekondêre skerms nie."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Skermverdeler"</string> - <string name="divider_title" msgid="5482989479865361192">"Skermverdeler"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Volskerm links"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Links 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Links 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sien en doen meer"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Sleep ’n ander program in vir verdeelde skerm"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik buite ’n program om dit te herposisioneer"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Het dit"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vou uit vir meer inligting."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Kanselleer"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Herbegin"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Moenie weer wys nie"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dubbeltik om hierdie app te skuif"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimeer"</string> <string name="minimize_button_text" msgid="271592547935841753">"Maak klein"</string> <string name="close_button_text" msgid="2913281996024033299">"Maak toe"</string> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 9ed281fb3686..2559c6fe148d 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"መጠን ይቀይሩ"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"መተግበሪያ ከተከፈለ ማያ ገጽ ጋር ላይሠራ ይችላል"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ይህ መተግበሪያ መከፈት የሚችለው በ1 መስኮት ብቻ ነው።"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"መተግበሪያ በሁለተኛ ማሳያዎች ላይ ማስጀመርን አይደግፍም።"</string> - <string name="accessibility_divider" msgid="703810061635792791">"የተከፈለ የማያ ገጽ ከፋይ"</string> - <string name="divider_title" msgid="5482989479865361192">"የተከፈለ የማያ ገጽ ከፋይ"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"የግራ ሙሉ ማያ ገጽ"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ግራ 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ግራ 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ተጨማሪ ይመልከቱ እና ያድርጉ"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ለተከፈለ ማያ ገጽ ሌላ መተግበሪያ ይጎትቱ"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ቦታውን ለመቀየር ከመተግበሪያው ውጪ ሁለቴ መታ ያድርጉ"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ገባኝ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ለተጨማሪ መረጃ ይዘርጉ።"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ይቅር"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"እንደገና ያስጀምሩ"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ዳግም አታሳይ"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"አስፋ"</string> <string name="minimize_button_text" msgid="271592547935841753">"አሳንስ"</string> <string name="close_button_text" msgid="2913281996024033299">"ዝጋ"</string> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 8fe0fb909197..2cbeb7cd9eff 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغيير الحجم"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"إخفاء"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"إظهار"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"قد لا يعمل التطبيق بشكل سليم في وضع \"تقسيم الشاشة\"."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"التطبيق لا يتيح تقسيم الشاشة."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"لا يمكن فتح هذا التطبيق إلا في نافذة واحدة."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"قد لا يعمل التطبيق على شاشة عرض ثانوية."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"لا يمكن تشغيل التطبيق على شاشات عرض ثانوية."</string> - <string name="accessibility_divider" msgid="703810061635792791">"أداة تقسيم الشاشة"</string> - <string name="divider_title" msgid="5482989479865361192">"أداة تقسيم الشاشة"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"عرض النافذة اليسرى بملء الشاشة"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ضبط حجم النافذة اليسرى ليكون ٧٠%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ضبط حجم النافذة اليسرى ليكون ٥٠%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"نقل إلى أسفل اليسار"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"إعدادات <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"إغلاق فقاعة المحادثة"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"عدم إظهار فقاعات المحادثات"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"عدم عرض المحادثة كفقاعة محادثة"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"الدردشة باستخدام فقاعات المحادثات"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"استخدام تطبيقات متعدّدة في وقت واحد"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"انقر مرّتين خارج تطبيق لتغيير موضعه."</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"حسنًا"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"التوسيع للحصول على مزيد من المعلومات"</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"إلغاء"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"إعادة التشغيل"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"عدم عرض مربّع حوار التأكيد مجددًا"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"تكبير"</string> <string name="minimize_button_text" msgid="271592547935841753">"تصغير"</string> <string name="close_button_text" msgid="2913281996024033299">"إغلاق"</string> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index a8480ebbf64d..160c5a623771 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"আকাৰ সলনি কৰক"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"লুকুৱাওক"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"দেখুৱাওক"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"এপ্টোৱে বিভাজিত স্ক্ৰীনৰ সৈতে কাম নকৰিব পাৰে।"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"এপ্টোৱে বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"এই এপ্টো কেৱল ১ খন ৱিণ্ড’ত খুলিব পাৰি।"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"গৌণ ডিছপ্লেত এপ্ লঞ্চ কৰিব নোৱাৰি।"</string> - <string name="accessibility_divider" msgid="703810061635792791">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string> - <string name="divider_title" msgid="5482989479865361192">"বিভাজিত স্ক্ৰীনৰ বিভাজক"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাওঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"বাওঁফালৰ স্ক্ৰীনখন ৭০% কৰক"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"বাওঁফালৰ স্ক্ৰীনখন ৫০% কৰক"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"চাওক আৰু অধিক কৰক"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"বিভাজিত স্ক্ৰীনৰ বাবে অন্য এটা এপ্ টানি আনি এৰক"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"এপ্টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ বাহিৰত দুবাৰ টিপক"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"বুজি পালোঁ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"অধিক তথ্যৰ বাবে বিস্তাৰ কৰক।"</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"বাতিল কৰক"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ৰিষ্টাৰ্ট কৰক"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"পুনৰাই নেদেখুৱাব"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"এই এপ্টো স্থানান্তৰ কৰিবলৈ দুবাৰ টিপক"</string> <string name="maximize_button_text" msgid="1650859196290301963">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string> <string name="minimize_button_text" msgid="271592547935841753">"মিনিমাইজ কৰক"</string> <string name="close_button_text" msgid="2913281996024033299">"বন্ধ কৰক"</string> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index b158cdd4b0d3..6e2fd53d1e0a 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ölçüsünü dəyişin"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Güvənli məkanda saxlayın"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Güvənli məkandan çıxarın"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Tətbiq bölünmüş ekran ilə işləməyə bilər."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Tətbiq ekran bölünməsini dəstəkləmir."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu tətbiq yalnız 1 pəncərədə açıla bilər."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Tətbiq ikinci ekranda işləməyə bilər."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Tətbiq ikinci ekranda başlamağı dəstəkləmir."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcısı"</string> - <string name="divider_title" msgid="5482989479865361192">"Bölünmüş ekran ayırıcısı"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Sol tam ekran"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Sol 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sol 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ardını görün və edin"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Bölünmüş ekrandan istifadə etmək üçün başqa tətbiqi sürüşdürüb gətirin"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tətbiqin yerini dəyişmək üçün kənarına iki dəfə toxunun"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ətraflı məlumat üçün genişləndirin."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Ləğv edin"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Yenidən başladın"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Yenidən göstərməyin"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Böyüdün"</string> <string name="minimize_button_text" msgid="271592547935841753">"Kiçildin"</string> <string name="close_button_text" msgid="2913281996024033299">"Bağlayın"</string> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index 954d34fdfa5a..f0bfbad156ef 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promenite veličinu"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavite u tajnu memoriju"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Uklonite iz tajne memorije"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi sa podeljenim ekranom."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podeljeni ekran."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova aplikacija može da se otvori samo u jednom prozoru."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionisati na sekundarnom ekranu."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Razdelnik podeljenog ekrana"</string> - <string name="divider_title" msgid="5482989479865361192">"Razdelnik podeljenog ekrana"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Režim celog ekrana za levi ekran"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Levi ekran 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi ekran 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vidite i uradite više"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Prevucite drugu aplikaciju da biste koristili podeljeni ekran"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste promenili njenu poziciju"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za još informacija."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Otkaži"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartuj"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dvaput dodirnite da biste premestili ovu aplikaciju"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Uvećajte"</string> <string name="minimize_button_text" msgid="271592547935841753">"Umanjite"</string> <string name="close_button_text" msgid="2913281996024033299">"Zatvorite"</string> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index cda6e39180fe..65bd7b3585f7 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змяніць памер"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Схаваць"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Паказаць"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Праграма можа не працаваць у рэжыме падзеленага экрана."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Праграма не падтрымлівае функцыю дзялення экрана."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Гэту праграму можна адкрыць толькі ў адным акне."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Праграма можа не працаваць на дадатковых экранах."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Праграма не падтрымлівае запуск на дадатковых экранах."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Раздзяляльнік падзеленага экрана"</string> - <string name="divider_title" msgid="5482989479865361192">"Раздзяляльнік падзеленага экрана"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левы экран – поўнаэкранны рэжым"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левы экран – 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левы экран – 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перамясціць правей і ніжэй"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Налады \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Адхіліць апавяшчэнне"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Выключыць усплывальныя апавяшчэнні"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Усплывальныя апавяшчэнні"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя апавяшчэнні. Націсніце, каб адкрыць усплывальнае апавяшчэнне. Перацягніце яго, каб перамясціць."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Адначасова выконвайце розныя задачы"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Перацягніце іншую праграму, каб выкарыстоўваць падзелены экран"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двойчы націсніце экран па-за праграмай, каб перамясціць яе"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Зразумела"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгарнуць для дадатковай інфармацыі"</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Скасаваць"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перазапусціць"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больш не паказваць"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Разгарнуць"</string> <string name="minimize_button_text" msgid="271592547935841753">"Згарнуць"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрыць"</string> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index a7757c649c89..0de565058d0f 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Преоразмеряване"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Съхраняване"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Отмяна на съхраняването"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Приложението може да не работи в режим на разделен екран."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложението не поддържа разделен екран."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Това приложение може да се отвори само в 1 прозорец."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Възможно е приложението да не работи на алтернативни дисплеи."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложението не поддържа използването на алтернативни дисплеи."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Разделител в режима за разделен екран"</string> - <string name="divider_title" msgid="5482989479865361192">"Разделител в режима за разделен екран"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ляв екран: Показване на цял екран"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ляв екран: 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ляв екран: 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Преглеждайте и правете повече неща"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Преместете друго приложение с плъзгане, за да преминете в режим за разделен екран"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Докоснете два пъти извън дадено приложение, за да промените позицията му"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Разбрах"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгъване за още информация."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Отказ"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартиране"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Да не се показва отново"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Увеличаване"</string> <string name="minimize_button_text" msgid="271592547935841753">"Намаляване"</string> <string name="close_button_text" msgid="2913281996024033299">"Затваряне"</string> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index f3f80b830cff..da206d69090d 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"রিসাইজ করুন"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"স্ট্যাস করুন"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"আনস্ট্যাস করুন"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"অ্যাপটি স্প্লিট স্ক্রিনে কাজ নাও করতে পারে।"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"অ্যাপ্লিকেশান বিভক্ত-স্ক্রিন সমর্থন করে না৷"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"এই অ্যাপটি শুধু ১টি উইন্ডোয় খোলা যেতে পারে।"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"সেকেন্ডারি ডিসপ্লেতে অ্যাপটি কাজ নাও করতে পারে।"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"সেকেন্ডারি ডিসপ্লেতে অ্যাপ লঞ্চ করা যাবে না।"</string> - <string name="accessibility_divider" msgid="703810061635792791">"বিভক্ত-স্ক্রিন বিভাজক"</string> - <string name="divider_title" msgid="5482989479865361192">"স্প্লিট স্ক্রিন বিভাজক"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাঁ দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"৭০% বাকি আছে"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"৫০% বাকি আছে"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"দেখুন ও আরও অনেক কিছু করুন"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"স্প্লিট স্ক্রিনের জন্য অন্য অ্যাপে টেনে আনুন"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"কোনও অ্যাপের স্থান পরিবর্তন করতে তার বাইরে ডবল ট্যাপ করুন"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"বুঝেছি"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"আরও তথ্যের জন্য বড় করুন।"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"বাতিল করুন"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"রিস্টার্ট করুন"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"আর দেখতে চাই না"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"বড় করুন"</string> <string name="minimize_button_text" msgid="271592547935841753">"ছোট করুন"</string> <string name="close_button_text" msgid="2913281996024033299">"বন্ধ করুন"</string> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index e7fa212334a8..26ea7cc3f804 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavljanje u stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vađenje iz stasha"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi na podijeljenom ekranu."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava dijeljenje ekrana."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova aplikacija se može otvoriti samo u 1 prozoru."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće raditi na sekundarnom ekranu."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik podijeljenog ekrana"</string> - <string name="divider_title" msgid="5482989479865361192">"Razdjelnik podijeljenog ekrana"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevo cijeli ekran"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Lijevo 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevo 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Pogledajte i učinite više"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Prevucite još jednu aplikaciju za podijeljeni ekran"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da promijenite njen položaj"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Razumijem"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za više informacija."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Otkaži"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Ponovo pokreni"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dvaput dodirnite da biste premjestili ovu aplikaciju"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziranje"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimiziranje"</string> <string name="close_button_text" msgid="2913281996024033299">"Zatvaranje"</string> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index 10216675887b..e086adf8357a 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Amaga"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"És possible que l\'aplicació no funcioni amb la pantalla dividida."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'aplicació no admet la pantalla dividida."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aquesta aplicació només pot obrir-se en 1 finestra."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"És possible que l\'aplicació no funcioni en una pantalla secundària."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'aplicació no es pot obrir en pantalles secundàries."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalles"</string> - <string name="divider_title" msgid="5482989479865361192">"Separador de pantalla dividida"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla esquerra completa"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Pantalla esquerra al 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pantalla esquerra al 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta i fes més coses"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrossega una altra aplicació per utilitzar la pantalla dividida"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Fes doble toc fora d\'una aplicació per canviar-ne la posició"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entesos"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Desplega per obtenir més informació."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel·la"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reinicia"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No ho tornis a mostrar"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maximitza"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimitza"</string> <string name="close_button_text" msgid="2913281996024033299">"Tanca"</string> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index d6e4f9f973b5..abefd9f1cf6c 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Změnit velikost"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Uložit"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušit uložení"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikace v režimu rozdělené obrazovky nemusí fungovat."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikace nepodporuje režim rozdělené obrazovky."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Tuto aplikaci lze otevřít jen na jednom okně."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikace na sekundárním displeji nemusí fungovat."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikace nepodporuje spuštění na sekundárních displejích."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Čára rozdělující obrazovku"</string> - <string name="divider_title" msgid="5482989479865361192">"Čára rozdělující obrazovku"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Levá část na celou obrazovku"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % vlevo"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % vlevo"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Přesunout vpravo dolů"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Nastavení <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Zavřít bublinu"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Nezobrazovat bubliny"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nezobrazovat konverzaci v bublinách"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatujte pomocí bublin"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nové konverzace se zobrazují jako plovoucí ikony, neboli bubliny. Klepnutím bublinu otevřete. Přetažením ji posunete."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lepší zobrazení a více možností"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Přetáhnutím druhé aplikace použijete rozdělenou obrazovku"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikaci změníte její umístění"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozbalením zobrazíte další informace."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Zrušit"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartovat"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Tuto zprávu příště nezobrazovat"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovat"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimalizovat"</string> <string name="close_button_text" msgid="2913281996024033299">"Zavřít"</string> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index da8723f8742d..adf29cad1b2f 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Rediger størrelse"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skjul"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vis"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen fungerer muligvis ikke i opdelt skærm."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen understøtter ikke opdelt skærm."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denne app kan kun åbnes i 1 vindue."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer muligvis ikke på sekundære skærme."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke åbnes på sekundære skærme."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Adskiller til opdelt skærm"</string> - <string name="divider_title" msgid="5482989479865361192">"Adskiller til opdelt skærm"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vis venstre del i fuld skærm"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Venstre 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Venstre 50 %"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flyt ned til højre"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Indstillinger for <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Afvis boble"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Stop med at vise bobler"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Vis ikke samtaler i bobler"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat ved hjælp af bobler"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som svævende ikoner eller bobler. Tryk for at åbne boblen. Træk for at flytte den."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gør mere"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Træk en anden app hertil for at bruge opdelt skærm"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryk to gange uden for en app for at justere dens placering"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Udvid for at få flere oplysninger."</string> @@ -95,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuller"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Genstart"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vis ikke igen"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Tryk to gange for at flytte appen"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimér"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string> <string name="close_button_text" msgid="2913281996024033299">"Luk"</string> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index b2b761973fb0..46101570caa2 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Größe anpassen"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"In Stash legen"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Aus Stash entfernen"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Die App funktioniert unter Umständen im Modus für geteilten Bildschirm nicht."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Diese App kann nur in einem einzigen Fenster geöffnet werden."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Die App unterstützt den Start auf sekundären Displays nicht."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Bildschirmteiler"</string> - <string name="divider_title" msgid="5482989479865361192">"Bildschirmteiler"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vollbild links"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % links"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % links"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Mehr sehen und erledigen"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Weitere App hineinziehen, um den Bildschirm zu teilen"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Außerhalb einer App doppeltippen, um die Position zu ändern"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ok"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Für weitere Informationen maximieren."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Abbrechen"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Neu starten"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nicht mehr anzeigen"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maximieren"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimieren"</string> <string name="close_button_text" msgid="2913281996024033299">"Schließen"</string> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index a09a647d4a0b..4ac9f7f63865 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Αλλαγή μεγέθους"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Απόκρυψη"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Κατάργηση απόκρυψης"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Η εφαρμογή ενδέχεται να μην λειτουργεί με διαχωρισμό οθόνης."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Αυτή η εφαρμογή μπορεί να ανοιχθεί μόνο σε 1 παράθυρο."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Η εφαρμογή δεν υποστηρίζει την εκκίνηση σε δευτερεύουσες οθόνες."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Διαχωριστικό οθόνης"</string> - <string name="divider_title" msgid="5482989479865361192">"Διαχωριστικό οθόνης"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Αριστερή πλήρης οθόνη"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Αριστερή 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Αριστερή 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Δείτε και κάντε περισσότερα"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Σύρετε σε μια άλλη εφαρμογή για διαχωρισμό οθόνης"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Πατήστε δύο φορές έξω από μια εφαρμογή για να αλλάξετε τη θέση της"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Το κατάλαβα"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ανάπτυξη για περισσότερες πληροφορίες."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Ακύρωση"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Επανεκκίνηση"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Να μην εμφανιστεί ξανά"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Διπλό πάτημα για μεταφορά αυτής της εφαρμογής"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Μεγιστοποίηση"</string> <string name="minimize_button_text" msgid="271592547935841753">"Ελαχιστοποίηση"</string> <string name="close_button_text" msgid="2913281996024033299">"Κλείσιμο"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index 0a0b30dc8407..8dee9ae82c5f 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string> - <string name="divider_title" msgid="5482989479865361192">"Split screen divider"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Double-tap to move this app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index 33f533398531..137ebe47c0b5 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -32,13 +32,13 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string> + <string name="dock_forced_resizable" msgid="7429086980048964687">"App may not work with split screen"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App does not support split screen"</string> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in 1 window."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Split-screen divider"</string> - <string name="divider_title" msgid="5482989479865361192">"Split-screen divider"</string> + <string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string> + <string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> @@ -85,7 +85,7 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string> + <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string> @@ -94,6 +94,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don’t show again"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Double-tap to move this app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximize"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimize"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index 0a0b30dc8407..8dee9ae82c5f 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string> - <string name="divider_title" msgid="5482989479865361192">"Split screen divider"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Double-tap to move this app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index 0a0b30dc8407..8dee9ae82c5f 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string> - <string name="divider_title" msgid="5482989479865361192">"Split screen divider"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Double-tap to move this app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml index 69823f990f3b..b63af4c69cdd 100644 --- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml @@ -32,13 +32,13 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string> + <string name="dock_forced_resizable" msgid="7429086980048964687">"App may not work with split screen"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"App does not support split screen"</string> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in 1 window."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Split-screen divider"</string> - <string name="divider_title" msgid="5482989479865361192">"Split-screen divider"</string> + <string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string> + <string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> @@ -85,7 +85,7 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string> + <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Drag in another app for split screen"</string> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string> @@ -94,6 +94,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don’t show again"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Double-tap to move this app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximize"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimize"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index b7b31f459335..6faae3c1b83c 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar el tamaño"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Almacenar de manera segura"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Dejar de almacenar de manera segura"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la app no funcione en el modo de pantalla dividida."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La app no es compatible con la función de pantalla dividida."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta app solo puede estar abierta en 1 ventana."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la app no funcione en una pantalla secundaria."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La app no puede iniciarse en pantallas secundarias."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string> - <string name="divider_title" msgid="5482989479865361192">"Divisor de pantalla dividida"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Izquierda: 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda: 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Aprovecha más"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra otra app para el modo de pantalla dividida"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Presiona dos veces fuera de una app para cambiar su ubicación"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expande para obtener más información."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index 5ef402c35bfa..8ec63b9bc23c 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"No esconder"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la aplicación no funcione con la pantalla dividida."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La aplicación no admite la pantalla dividida."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta aplicación solo puede abrirse en una ventana."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la aplicación no funcione en una pantalla secundaria."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La aplicación no se puede abrir en pantallas secundarias."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Dividir la pantalla"</string> - <string name="divider_title" msgid="5482989479865361192">"Divisor de pantalla dividida"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Izquierda 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta más información y haz más"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra otra aplicación para activar la pantalla dividida"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dos veces fuera de una aplicación para cambiarla de posición"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mostrar más información"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index e083be417a90..5323bb5eec22 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Suuruse muutmine"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Pane hoidlasse"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Eemalda hoidlast"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Rakendus ei pruugi poolitatud ekraaniga töötada."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Rakendus ei toeta jagatud ekraani."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Selle rakenduse saab avada ainult ühes aknas."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Rakendus ei pruugi teisesel ekraanil töötada."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Rakendus ei toeta teisestel ekraanidel käivitamist."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Ekraanijagaja"</string> - <string name="divider_title" msgid="5482989479865361192">"Ekraanijagaja"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasak täisekraan"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vasak: 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasak: 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vaadake ja tehke rohkem"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Lohistage muusse rakendusse, et jagatud ekraanikuva kasutada"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Topeltpuudutage rakendusest väljaspool, et selle asendit muuta"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Laiendage lisateabe saamiseks."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Tühista"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Taaskäivita"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ära kuva uuesti"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimeeri"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimeeri"</string> <string name="close_button_text" msgid="2913281996024033299">"Sule"</string> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index e0922e4d5f5a..e7bdd8010727 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Aldatu tamaina"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Gorde"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ez gorde"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikazioak ez du onartzen pantaila zatitua"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Leiho bakar batean ireki daiteke aplikazioa."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikazioa ezin da abiarazi bigarren mailako pantailatan."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Pantaila-zatitzailea"</string> - <string name="divider_title" msgid="5482989479865361192">"Pantaila-zatitzailea"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ezarri ezkerraldea pantaila osoan"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ezarri ezkerraldea % 70en"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ezarri ezkerraldea % 50en"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ikusi eta egin gauza gehiago"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Pantaila zatituta ikusteko, arrastatu beste aplikazio bat"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren kanpoaldea"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ados"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Informazio gehiago lortzeko, zabaldu hau."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Utzi"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Berrabiarazi"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ez erakutsi berriro"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Sakatu birritan aplikazioa mugitzeko"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizatu"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizatu"</string> <string name="close_button_text" msgid="2913281996024033299">"Itxi"</string> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index e847f6e05187..c6ad275e5b18 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغییر اندازه"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"مخفیسازی"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"لغو مخفیسازی"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن است برنامه با «صفحهٔ دونیمه» کار نکند."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"برنامه از تقسیم صفحه پشتیبانی نمیکند."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"این برنامه فقط در ۱ پنجره میتواند باز شود."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن است برنامه در نمایشگر ثانویه کار نکند."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"برنامه از راهاندازی در نمایشگرهای ثانویه پشتیبانی نمیکند."</string> - <string name="accessibility_divider" msgid="703810061635792791">"تقسیمکننده صفحه"</string> - <string name="divider_title" msgid="5482989479865361192">"تقسیمکننده صفحهٔ دونیمه"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"تمامصفحه چپ"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"٪۷۰ چپ"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"٪۵۰ چپ"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن ضربه بزنید"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن ضربه بزنید."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"از چندین برنامه بهطور همزمان استفاده کنید"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"برای حالت صفحهٔ دونیمه، در برنامهای دیگر بکشید"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابهجا کردن برنامه، بیرون از آن دوضربه بزنید"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجهام"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"برای اطلاعات بیشتر، گسترده کنید."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"لغو کردن"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"بازراهاندازی"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوباره نشان داده نشود"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"برای جابهجایی این برنامه، دوضربه بزنید"</string> <string name="maximize_button_text" msgid="1650859196290301963">"بزرگ کردن"</string> <string name="minimize_button_text" msgid="271592547935841753">"کوچک کردن"</string> <string name="close_button_text" msgid="2913281996024033299">"بستن"</string> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 14b35566c938..b9f72721d4ed 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Muuta kokoa"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Lisää turvasäilytykseen"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poista turvasäilytyksestä"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Sovellus ei ehkä toimi jaetulla näytöllä."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Sovellus ei tue jaetun näytön tilaa."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Tämän sovelluksen voi avata vain yhdessä ikkunassa."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Sovellus ei ehkä toimi toissijaisella näytöllä."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Sovellus ei tue käynnistämistä toissijaisilla näytöillä."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Näytön jakaja"</string> - <string name="divider_title" msgid="5482989479865361192">"Näytönjakaja"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasen koko näytölle"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vasen 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasen 50 %"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Siirrä oikeaan alareunaan"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: asetukset"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ohita kupla"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Älä näytä puhekuplia"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Älä näytä kuplia keskusteluista"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chattaile kuplien avulla"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Näe ja tee enemmän"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Käytä jaettua näyttöä vetämällä tähän toinen sovellus"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kaksoisnapauta sovelluksen ulkopuolella, jos haluat siirtää sitä"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Katso lisätietoja laajentamalla."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Peru"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Käynnistä uudelleen"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Älä näytä uudelleen"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Suurenna"</string> <string name="minimize_button_text" msgid="271592547935841753">"Pienennä"</string> <string name="close_button_text" msgid="2913281996024033299">"Sulje"</string> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index df3e345310f0..8db7790c72b1 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ajouter à la réserve"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Retirer de la réserve"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'application n\'est pas compatible avec l\'écran partagé."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Cette application ne peut être ouverte que dans une fenêtre."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string> - <string name="divider_title" msgid="5482989479865361192">"Séparateur d\'écran partagé"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Plein écran à la gauche"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % à la gauche"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % à la gauche"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Déplacer dans coin inf. droit"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Paramètres <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignorer la bulle"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Ne pas afficher de bulles"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher les conversations dans des bulles"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Clavarder en utilisant des bulles"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et en faire plus"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Faites glisser une autre application pour utiliser l\'écran partagé"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Touchez deux fois à côté d\'une application pour la repositionner"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développer pour en savoir plus."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuler"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string> <string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string> <string name="close_button_text" msgid="2913281996024033299">"Fermer"</string> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index c86711e44618..8d4bccab9d9f 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Application incompatible avec l\'écran partagé."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Cette appli ne peut être ouverte que dans 1 fenêtre."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string> - <string name="divider_title" msgid="5482989479865361192">"Séparateur d\'écran partagé"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Écran de gauche en plein écran"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Écran de gauche à 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Écran de gauche à 50 %"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et interagir plus"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Appuyez deux fois en dehors d\'une appli pour la repositionner"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développez pour obtenir plus d\'informations"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuler"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string> <string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string> <string name="close_button_text" msgid="2913281996024033299">"Fermer"</string> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index a63930d2f10b..7c09c76f3185 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Non esconder"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Pode que a aplicación non funcione coa pantalla dividida."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A aplicación non é compatible coa función de pantalla dividida."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta aplicación só se pode abrir en 1 ventá."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É posible que a aplicación non funcione nunha pantalla secundaria."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A aplicación non se pode iniciar en pantallas secundarias."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string> - <string name="divider_title" msgid="5482989479865361192">"Divisor de pantalla dividida"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla completa á esquerda"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % á esquerda"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % á esquerda"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover á parte inferior dereita"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Configuración de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignorar burbulla"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Non mostrar burbullas"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mostrar a conversa como burbulla"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatear usando burbullas"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"As conversas novas aparecen como iconas flotantes ou burbullas. Toca para abrir a burbulla e arrastra para movela."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ver e facer máis"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arrastra outra aplicación para usar a pantalla dividida"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dúas veces fóra da aplicación para cambiala de posición"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Despregar para obter máis información."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrar outra vez"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Pechar"</string> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index 8de29c13c800..f968bd5be1a8 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"કદ બદલો"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"છુપાવો"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"બતાવો"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"વિભાજિત-સ્ક્રીન સાથે ઍપ કદાચ કામ ન કરે."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ઍપ્લિકેશન સ્ક્રીન-વિભાજનનું સમર્થન કરતી નથી."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"આ ઍપ માત્ર 1 વિન્ડોમાં ખોલી શકાય છે."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર કદાચ કામ ન કરે."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર લૉન્ચનું સમર્થન કરતી નથી."</string> - <string name="accessibility_divider" msgid="703810061635792791">"સ્પ્લિટ-સ્ક્રીન વિભાજક"</string> - <string name="divider_title" msgid="5482989479865361192">"સ્ક્રીનને વિભાજિત કરતું વિભાજક"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ડાબી પૂર્ણ સ્ક્રીન"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ડાબે 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ડાબે 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"જુઓ અને બીજું ઘણું કરો"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"સ્ક્રીન વિભાજન માટે કોઈ અન્ય ઍપમાં ખેંચો"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બહાર બે વાર ટૅપ કરો"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"સમજાઈ ગયું"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"વધુ માહિતી માટે મોટું કરો."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"રદ કરો"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ફરી શરૂ કરો"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ફરીથી બતાવશો નહીં"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"મોટું કરો"</string> <string name="minimize_button_text" msgid="271592547935841753">"નાનું કરો"</string> <string name="close_button_text" msgid="2913281996024033299">"બંધ કરો"</string> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index d71824f4ca9f..805a8813844b 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदलें"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"छिपाएं"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"दिखाएं"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ऐप्लिकेशन शायद स्प्लिट स्क्रीन मोड में काम न करे."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ऐप विभाजित स्क्रीन का समर्थन नहीं करता है."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"इस ऐप्लिकेशन को सिर्फ़ एक विंडो में खोला जा सकता है."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर ऐप लॉन्च नहीं किया जा सकता."</string> - <string name="accessibility_divider" msgid="703810061635792791">"विभाजित स्क्रीन विभाजक"</string> - <string name="divider_title" msgid="5482989479865361192">"स्प्लिट स्क्रीन डिवाइडर"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"बाईं स्क्रीन को 70% बनाएं"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बाईं स्क्रीन को 50% बनाएं"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पूरी जानकारी लेकर, बेहतर तरीके से काम करें"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट स्क्रीन के लिए, दूसरे ऐप्लिकेशन को खींचें और छोड़ें"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बाहर दो बार टैप करें"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ज़्यादा जानकारी के लिए बड़ा करें."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"रद्द करें"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करें"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फिर से न दिखाएं"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"बड़ा करें"</string> <string name="minimize_button_text" msgid="271592547935841753">"विंडो छोटी करें"</string> <string name="close_button_text" msgid="2913281996024033299">"बंद करें"</string> diff --git a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml index 595435bcf8b8..e2f272c36329 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml @@ -18,7 +18,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="notification_channel_tv_pip" msgid="2576686079160402435">"पिक्चर में पिक्चर"</string> - <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(कोई शीर्षक कार्यक्रम नहीं)"</string> + <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(कोई टाइटल कार्यक्रम नहीं)"</string> <string name="pip_close" msgid="2955969519031223530">"बंद करें"</string> <string name="pip_fullscreen" msgid="7278047353591302554">"फ़ुल स्क्रीन"</string> <string name="pip_move" msgid="158770205886688553">"ले जाएं"</string> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index de4cac24aab8..69373348b41e 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sakrijte"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poništite sakrivanje"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podijeljeni zaslon."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova se aplikacija može otvoriti samo u jednom prozoru."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionirati na sekundarnom zaslonu."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim zaslonima."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik podijeljenog zaslona"</string> - <string name="divider_title" msgid="5482989479865361192">"Razdjelnik podijeljenog zaslona"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevi zaslon u cijeli zaslon"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Lijevi zaslon na 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevi zaslon na 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Gledajte i učinite više"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Povucite drugu aplikaciju unutra da biste podijelili zaslon"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste je premjestili"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Shvaćam"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite da biste saznali više."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Odustani"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Pokreni ponovno"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovno"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dvaput dodirnite da biste premjestili ovu aplikaciju"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziraj"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimiziraj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zatvori"</string> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index 667464f9523b..4ef9f465dc41 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Átméretezés"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Félretevés"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Félretevés megszüntetése"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ez az alkalmazás csak egy ablakban nyitható meg."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Az alkalmazást nem lehet másodlagos kijelzőn elindítani."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Elválasztó az osztott nézetben"</string> - <string name="divider_title" msgid="5482989479865361192">"Elválasztó az osztott nézetben"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Bal oldali teljes képernyőre"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Bal oldali 70%-ra"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Bal oldali 50%-ra"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Több mindent láthat és tehet"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Koppintson duplán az alkalmazáson kívül az áthelyezéséhez"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Értem"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kibontással további információkhoz juthat."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Mégse"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Újraindítás"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne jelenjen meg többé"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Teljes méret"</string> <string name="minimize_button_text" msgid="271592547935841753">"Kis méret"</string> <string name="close_button_text" msgid="2913281996024033299">"Bezárás"</string> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index 4ea668c93f98..d01ff713c7c3 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Փոխել չափը"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Թաքցնել"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ցուցադրել"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում։"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Այս հավելվածը հնարավոր է բացել միայն մեկ պատուհանում։"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Հավելվածը չի աջակցում գործարկումը լրացուցիչ էկրանների վրա"</string> - <string name="accessibility_divider" msgid="703810061635792791">"Տրոհված էկրանի բաժանիչ"</string> - <string name="divider_title" msgid="5482989479865361192">"Տրոհված էկրանի բաժանիչ"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ձախ էկրանը՝ լիաէկրան"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ձախ էկրանը՝ 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ձախ էկրանը՝ 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Տեղափոխել ներքև՝ աջ"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – կարգավորումներ"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Փակել ամպիկը"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Ցույց չտալ ամպիկները"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Զրույցը չցուցադրել ամպիկի տեսքով"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Զրույցի ամպիկներ"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Նոր զրույցները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Միաժամանակ կատարեք մի քանի առաջադրանք"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Քաշեք մյուս հավելվածի մեջ՝ էկրանի տրոհումն օգտագործելու համար"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Եղավ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ծավալեք՝ ավելին իմանալու համար։"</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Չեղարկել"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Վերագործարկել"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Այլևս ցույց չտալ"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Ծավալել"</string> <string name="minimize_button_text" msgid="271592547935841753">"Ծալել"</string> <string name="close_button_text" msgid="2913281996024033299">"Փակել"</string> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index 8cd0bc5d2f3e..123e5b9ef7de 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah ukuran"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Batalkan stash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikasi mungkin tidak berfungsi dengan layar terpisah."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App tidak mendukung layar terpisah."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aplikasi ini hanya dapat dibuka di 1 jendela."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikasi mungkin tidak berfungsi pada layar sekunder."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikasi tidak mendukung peluncuran pada layar sekunder."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Pembagi layar terpisah"</string> - <string name="divider_title" msgid="5482989479865361192">"Pembagi layar terpisah"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Layar penuh di kiri"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kiri 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih banyak hal"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Tarik aplikasi lain untuk menggunakan layar terpisah"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketuk dua kali di luar aplikasi untuk mengubah posisinya"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Luaskan untuk melihat informasi selengkapnya."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Batal"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulai ulang"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Jangan tampilkan lagi"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimalkan"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimalkan"</string> <string name="close_button_text" msgid="2913281996024033299">"Tutup"</string> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index ae5e1823bbea..bd80936781d0 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Breyta stærð"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Geymsla"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Taka úr geymslu"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Hugsanlega virkar forritið ekki með skjáskiptingu."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Forritið styður ekki að skjánum sé skipt."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aðeins er hægt að opna þetta forrit í 1 glugga."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Hugsanlegt er að forritið virki ekki á öðrum skjá."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Forrit styður ekki opnun á öðrum skjá."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Skjáskipting"</string> - <string name="divider_title" msgid="5482989479865361192">"Skjáskipting"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vinstri á öllum skjánum"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vinstri 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vinstri 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Sjáðu og gerðu meira"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dragðu annað forrit inn til að nota skjáskiptingu"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ýttu tvisvar utan við forrit til að færa það"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ég skil"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Stækka til að sjá frekari upplýsingar."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Hætta við"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Endurræsa"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ekki sýna þetta aftur"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Stækka"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minnka"</string> <string name="close_button_text" msgid="2913281996024033299">"Loka"</string> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index 37551161f8d8..90e6a6feedf0 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ridimensiona"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Accantona"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Annulla accantonamento"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"L\'app potrebbe non funzionare con lo schermo diviso."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'app non supporta la modalità Schermo diviso."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Questa app può essere aperta soltanto in 1 finestra."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"L\'app potrebbe non funzionare su un display secondario."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'app non supporta l\'avvio su display secondari."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Strumento per schermo diviso"</string> - <string name="divider_title" msgid="5482989479865361192">"Strumento per schermo diviso"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Schermata sinistra a schermo intero"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Schermata sinistra al 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Schermata sinistra al 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sposta in basso a destra"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Impostazioni <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignora bolla"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Non mostrare i fumetti"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mettere la conversazione nella bolla"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatta utilizzando le bolle"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Le nuove conversazioni vengono mostrate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Visualizza più contenuti e fai di più"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trascina in un\'altra app per usare lo schermo diviso"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tocca due volte fuori da un\'app per riposizionarla"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Espandi per avere ulteriori informazioni."</string> @@ -95,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annulla"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Riavvia"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrare più"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Tocca due volte per spostare questa app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Ingrandisci"</string> <string name="minimize_button_text" msgid="271592547935841753">"Riduci a icona"</string> <string name="close_button_text" msgid="2913281996024033299">"Chiudi"</string> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index 9963acea93bc..8d5c4a4cad9f 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"שינוי גודל"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"הסתרה זמנית"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ביטול ההסתרה הזמנית"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ייתכן שהאפליקציה לא תפעל במסך מפוצל."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"האפליקציה אינה תומכת במסך מפוצל."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ניתן לפתוח את האפליקציה הזו רק בחלון אחד."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ייתכן שהאפליקציה לא תפעל במסך משני."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"האפליקציה אינה תומכת בהפעלה במסכים משניים."</string> - <string name="accessibility_divider" msgid="703810061635792791">"מחלק מסך מפוצל"</string> - <string name="divider_title" msgid="5482989479865361192">"מחלק מסך מפוצל"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"מסך שמאלי מלא"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"שמאלה 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"שמאלה 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"רוצה לראות ולעשות יותר?"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"צריך לגרור אפליקציה אחרת כדי להשתמש במסך מפוצל"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"צריך להקיש הקשה כפולה מחוץ לאפליקציה כדי למקם אותה מחדש"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"הבנתי"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"מרחיבים כדי לקבל מידע נוסף."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ביטול"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"הפעלה מחדש"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"אין צורך להציג את זה שוב"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"אפשר להקיש הקשה כפולה כדי להזיז את האפליקציה הזו"</string> <string name="maximize_button_text" msgid="1650859196290301963">"הגדלה"</string> <string name="minimize_button_text" msgid="271592547935841753">"מזעור"</string> <string name="close_button_text" msgid="2913281996024033299">"סגירה"</string> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index b7c30a387eed..6b1f6991afc5 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"サイズ変更"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"非表示"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"表示"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"アプリは分割画面では動作しないことがあります。"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"アプリで分割画面がサポートされていません。"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"このアプリはウィンドウが 1 つの場合のみ開くことができます。"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"アプリはセカンダリ ディスプレイでは動作しないことがあります。"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"アプリはセカンダリ ディスプレイでの起動に対応していません。"</string> - <string name="accessibility_divider" msgid="703810061635792791">"分割画面の分割線"</string> - <string name="divider_title" msgid="5482989479865361192">"分割画面の分割線"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左全画面"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"右下に移動"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> の設定"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"バブルを閉じる"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"バブルで表示しない"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"会話をバブルで表示しない"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"チャットでバブルを使う"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"表示を拡大して機能を強化"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"分割画面にするにはもう 1 つのアプリをドラッグしてください"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"位置を変えるにはアプリの外側をダブルタップしてください"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"開くと詳細が表示されます。"</string> @@ -95,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"キャンセル"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"再起動"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"次回から表示しない"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"ダブルタップすると、このアプリを移動できます"</string> <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string> <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"閉じる"</string> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 02cf02f870d0..05430e10f45f 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ზომის შეცვლა"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"გადანახვა"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"გადანახვის გაუქმება"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ამ აპის გახსნა შესაძლებელია მხოლოდ 1 ფანჯარაში."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"აპს არ გააჩნია მეორეული ეკრანის მხარდაჭერა."</string> - <string name="accessibility_divider" msgid="703810061635792791">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string> - <string name="divider_title" msgid="5482989479865361192">"ეკრანის გაყოფის გამყოფი"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"მარცხენა ნაწილის სრულ ეკრანზე გაშლა"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"მარცხენა ეკრანი — 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"მარცხენა ეკრანი — 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"მეტის ნახვა და გაკეთება"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ეკრანის გასაყოფად ჩავლებით გადაიტანეთ სხვა აპში"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ორმაგად შეეხეთ აპის გარშემო სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"გასაგებია"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"დამატებითი ინფორმაციისთვის გააფართოეთ."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"გაუქმება"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"გადატვირთვა"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"აღარ გამოჩნდეს"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"ამ აპის გადასატანად ორმაგად შეეხეთ მას"</string> <string name="maximize_button_text" msgid="1650859196290301963">"მაქსიმალურად გაშლა"</string> <string name="minimize_button_text" msgid="271592547935841753">"ჩაკეცვა"</string> <string name="close_button_text" msgid="2913281996024033299">"დახურვა"</string> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index b60c2314ab5e..7f006abbd0f5 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлшемін өзгерту"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Жасыру"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Көрсету"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Қолданба экранды бөлу режимінде жұмыс істемеуі мүмкін."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Қодланба бөлінген экранды қолдамайды."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Бұл қолданбаны тек 1 терезеден ашуға болады."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Қолданба қосымша дисплейде жұмыс істемеуі мүмкін."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Қолданба қосымша дисплейлерде іске қосуды қолдамайды."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Бөлінген экран бөлгіші"</string> - <string name="divider_title" msgid="5482989479865361192">"Бөлінген экран бөлгіші"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жағын толық экранға шығару"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% сол жақта"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% сол жақта"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Қосымша ақпаратты қарап, әрекеттер жасау"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Экранды бөлу үшін басқа қолданбаға сүйреңіз."</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Қолданбаның орнын өзгерту үшін одан тыс жерді екі рет түртіңіз."</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Түсінікті"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толығырақ ақпарат алу үшін терезені жайыңыз."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Бас тарту"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Өшіріп қосу"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Қайта көрсетілмесін"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Жаю"</string> <string name="minimize_button_text" msgid="271592547935841753">"Кішірейту"</string> <string name="close_button_text" msgid="2913281996024033299">"Жабу"</string> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index 29ff6c3abdbe..c1a3abd150e0 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ប្ដូរទំហំ"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"លាក់ជាបណ្ដោះអាសន្ន"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ឈប់លាក់ជាបណ្ដោះអាសន្ន"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"កម្មវិធីអាចនឹងមិនដំណើរការជាមួយមុខងារបំបែកអេក្រង់ទេ។"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"កម្មវិធីនេះអាចបើកនៅក្នុងវិនដូតែ 1 ប៉ុណ្ណោះ។"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"កម្មវិធីនេះប្រហែលជាមិនដំណើរការនៅលើអេក្រង់បន្ទាប់បន្សំទេ។"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"កម្មវិធីនេះមិនអាចចាប់ផ្តើមនៅលើអេក្រង់បន្ទាប់បន្សំបានទេ។"</string> - <string name="accessibility_divider" msgid="703810061635792791">"កម្មវិធីចែកអេក្រង់បំបែក"</string> - <string name="divider_title" msgid="5482989479865361192">"បន្ទាត់ខណ្ឌចែកអេក្រង់បំបែក"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"អេក្រង់ពេញខាងឆ្វេង"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ឆ្វេង 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ឆ្វេង 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបានដោះស្រាយបញ្ហានេះទេឬ?\nចុចដើម្បីត្រឡប់"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមានបញ្ហាពាក់ព័ន្ធនឹងកាមេរ៉ាទេឬ? ចុចដើម្បីច្រានចោល។"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"មើលឃើញ និងធ្វើបានកាន់តែច្រើន"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"អូសកម្មវិធីមួយទៀតចូល ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ចុចពីរដងនៅក្រៅកម្មវិធី ដើម្បីប្ដូរទីតាំងកម្មវិធីនោះ"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"យល់ហើយ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ពង្រីកដើម្បីទទួលបានព័ត៌មានបន្ថែម។"</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"បោះបង់"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ចាប់ផ្ដើមឡើងវិញ"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"កុំបង្ហាញម្ដងទៀត"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"ចុចពីរដង ដើម្បីផ្លាស់ទីកម្មវិធីនេះ"</string> <string name="maximize_button_text" msgid="1650859196290301963">"ពង្រីក"</string> <string name="minimize_button_text" msgid="271592547935841753">"បង្រួម"</string> <string name="close_button_text" msgid="2913281996024033299">"បិទ"</string> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index a67e066d0274..e04f00e55b17 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ಅನ್ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ವಿಭಜಿಸಿದ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ಆ್ಯಪ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ಈ ಆ್ಯಪ್ ಅನ್ನು 1 ವಿಂಡೋದಲ್ಲಿ ಮಾತ್ರ ತೆರೆಯಬಹುದು."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string> - <string name="accessibility_divider" msgid="703810061635792791">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string> - <string name="divider_title" msgid="5482989479865361192">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ಎಡ ಪೂರ್ಣ ಪರದೆ"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% ಎಡಕ್ಕೆ"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% ಎಡಕ್ಕೆ"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ನೋಡಿ ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ಗಾಗಿ ಮತ್ತೊಂದು ಆ್ಯಪ್ನಲ್ಲಿ ಎಳೆಯಿರಿ"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಹೊರಗೆ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ಸರಿ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ವಿಸ್ತೃತಗೊಳಿಸಿ."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ರದ್ದುಮಾಡಿ"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ಮರುಪ್ರಾರಂಭಿಸಿ"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಸರಿಸಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="maximize_button_text" msgid="1650859196290301963">"ಹಿಗ್ಗಿಸಿ"</string> <string name="minimize_button_text" msgid="271592547935841753">"ಕುಗ್ಗಿಸಿ"</string> <string name="close_button_text" msgid="2913281996024033299">"ಮುಚ್ಚಿರಿ"</string> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 0b88d7ac2c88..0ebeef1befa1 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"크기 조절"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"숨기기"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"숨기기 취소"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"앱이 분할 화면에서 작동하지 않을 수 있습니다."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"앱이 화면 분할을 지원하지 않습니다."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"이 앱은 창 1개에서만 열 수 있습니다."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"앱이 보조 디스플레이에서의 실행을 지원하지 않습니다."</string> - <string name="accessibility_divider" msgid="703810061635792791">"화면 분할기"</string> - <string name="divider_title" msgid="5482989479865361192">"화면 분할기"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"왼쪽 화면 전체화면"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"왼쪽 화면 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"왼쪽 화면 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"더 많은 정보를 보고 더 많은 작업을 처리하세요"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"화면 분할을 사용하려면 다른 앱을 드래그해 가져옵니다."</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"앱 위치를 조정하려면 앱 외부를 두 번 탭합니다."</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"추가 정보는 펼쳐서 확인하세요."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"취소"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"다시 시작"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"다시 표시 안함"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"최대화"</string> <string name="minimize_button_text" msgid="271592547935841753">"최소화"</string> <string name="close_button_text" msgid="2913281996024033299">"닫기"</string> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index 683a90333b4a..d20f21060ad7 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлчөмүн өзгөртүү"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сейфке салуу"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Сейфтен чыгаруу"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Колдонмодо экран бөлүнбөшү мүмкүн."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Колдонмодо экран бөлүнбөйт."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Бул колдонмону 1 терезеде гана ачууга болот."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Колдонмо кошумча экранда иштебей коюшу мүмкүн."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Колдонмону кошумча экрандарда иштетүүгө болбойт."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Экранды бөлгүч"</string> - <string name="divider_title" msgid="5482989479865361192">"Экранды бөлгүч"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жактагы экранды толук экран режимине өткөрүү"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Сол жактагы экранды 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Сол жактагы экранды 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Көрүп, көбүрөөк нерселерди жасаңыз"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Экранды бөлүү үчүн башка колдонмону сүйрөңүз"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Колдонмону жылдыруу үчүн сырт жагын эки жолу таптаңыз"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Түшүндүм"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толук маалымат алуу үчүн жайып көрүңүз."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Токтотуу"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Өчүрүп күйгүзүү"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Экинчи көрүнбөсүн"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Чоңойтуу"</string> <string name="minimize_button_text" msgid="271592547935841753">"Кичирейтүү"</string> <string name="close_button_text" msgid="2913281996024033299">"Жабуу"</string> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index c3114100b410..064717a8faf0 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ປ່ຽນຂະໜາດ"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ເກັບໄວ້ບ່ອນເກັບສ່ວນຕົວ"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ເອົາອອກຈາກບ່ອນເກັບສ່ວນຕົວ"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບການແບ່ງໜ້າຈໍ."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ແອັບນີ້ສາມາດເປີດໄດ້ໃນ 1 ໜ້າຈໍເທົ່ານັ້ນ."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ແອັບບໍ່ຮອງຮັບການເປີດໃນໜ້າຈໍທີສອງ."</string> - <string name="accessibility_divider" msgid="703810061635792791">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string> - <string name="divider_title" msgid="5482989479865361192">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ເຕັມໜ້າຈໍຊ້າຍ"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ຊ້າຍ 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ຊ້າຍ 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອປິດໄວ້."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ເບິ່ງ ແລະ ເຮັດຫຼາຍຂຶ້ນ"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ລາກແອັບອື່ນເຂົ້າມາເພື່ອແບ່ງໜ້າຈໍ"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ແຕະສອງເທື່ອໃສ່ນອກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ເຂົ້າໃຈແລ້ວ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ຂະຫຍາຍເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ຍົກເລີກ"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ຣີສະຕາດ"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ບໍ່ຕ້ອງສະແດງອີກ"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"ແຕະສອງເທື່ອເພື່ອຍ້າຍແອັບນີ້"</string> <string name="maximize_button_text" msgid="1650859196290301963">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string> <string name="minimize_button_text" msgid="271592547935841753">"ຫຍໍ້ລົງ"</string> <string name="close_button_text" msgid="2913281996024033299">"ປິດ"</string> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index be8e247a8cbe..12a81b67e9ec 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Pakeisti dydį"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslėpti"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Nebeslėpti"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Programa gali neveikti naudojant išskaidyto ekrano režimą."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programoje nepalaikomas skaidytas ekranas."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Šią programą galima atidaryti tik viename lange."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Programa gali neveikti antriniame ekrane."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programa nepalaiko paleisties antriniuose ekranuose."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Skaidyto ekrano daliklis"</string> - <string name="divider_title" msgid="5482989479865361192">"Skaidyto ekrano daliklis"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kairysis ekranas viso ekrano režimu"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kairysis ekranas 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kairysis ekranas 50 %"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daugiau turinio ir funkcijų"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Vilkite kitoje programoje, kad galėtumėte naudoti išskaidyto ekrano režimą"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dukart palieskite už programos ribų, kad pakeistumėte jos poziciją"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Supratau"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Išskleiskite, jei reikia daugiau informacijos."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Atšaukti"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Paleisti iš naujo"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Daugiau neberodyti"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dukart palieskite, kad perkeltumėte šią programą"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Padidinti"</string> <string name="minimize_button_text" msgid="271592547935841753">"Sumažinti"</string> <string name="close_button_text" msgid="2913281996024033299">"Uždaryti"</string> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index d6a1f1626b64..102f3c82dd0a 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Mainīt lielumu"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslēpt"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Rādīt"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Iespējams, lietotne nedarbosies ekrāna sadalīšanas režīmā."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Šo lietotni var atvērt tikai vienā logā."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Lietotne, iespējams, nedarbosies sekundārajā displejā."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Lietotnē netiek atbalstīta palaišana sekundārajos displejos."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Ekrāna sadalītājs"</string> - <string name="divider_title" msgid="5482989479865361192">"Ekrāna sadalītājs"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kreisā daļa pa visu ekrānu"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Pa kreisi 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pa kreisi 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Uzziniet un paveiciet vairāk"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Lai izmantotu sadalītu ekrānu, ievelciet vēl vienu lietotni"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Lai pārvietotu lietotni, veiciet dubultskārienu ārpus lietotnes"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Labi"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Izvērsiet, lai iegūtu plašāku informāciju."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Atcelt"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartēt"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vairs nerādīt"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimizēt"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizēt"</string> <string name="close_button_text" msgid="2913281996024033299">"Aizvērt"</string> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index 385dc327bfad..1adb7aab2f34 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промени големина"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сокријте"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Прикажете"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликацијата може да не работи со поделен екран."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликацијата не поддржува поделен екран."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Апликацијава може да се отвори само во еден прозорец."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликацијата може да не функционира на друг екран."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликацијата не поддржува стартување на други екрани."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Разделник на поделен екран"</string> - <string name="divider_title" msgid="5482989479865361192">"Разделник на поделен екран"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левиот на цел екран"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левиот 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левиот 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Погледнете и направете повеќе"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Повлечете во друга апликација за поделен екран"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Допрете двапати надвор од некоја апликација за да ја преместите"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Сфатив"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширете за повеќе информации."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Откажи"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартирај"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не прикажувај повторно"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Допрете двапати за да ја поместите апликацијава"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Зголеми"</string> <string name="minimize_button_text" msgid="271592547935841753">"Минимизирај"</string> <string name="close_button_text" msgid="2913281996024033299">"Затвори"</string> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index 561806c64fef..923fbc252f0e 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"വലുപ്പം മാറ്റുക"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"സ്റ്റാഷ് ചെയ്യൽ"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"അൺസ്റ്റാഷ് ചെയ്യൽ"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"സ്ക്രീൻ വിഭജന മോഡിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ഈ ആപ്പ് ഒരു വിൻഡോയിൽ മാത്രമേ തുറക്കാനാകൂ."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"രണ്ടാം ഡിസ്പ്ലേകളിൽ സമാരംഭിക്കുന്നതിനെ ആപ്പ് അനുവദിക്കുന്നില്ല."</string> - <string name="accessibility_divider" msgid="703810061635792791">"സ്പ്ലിറ്റ്-സ്ക്രീൻ ഡിവൈഡർ"</string> - <string name="divider_title" msgid="5482989479865361192">"സ്ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ഇടത് പൂർണ്ണ സ്ക്രീൻ"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ഇടത് 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ഇടത് 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"കൂടുതൽ കാണുക, ചെയ്യുക"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"സ്ക്രീൻ വിഭജന മോഡിന്, മറ്റൊരു ആപ്പ് വലിച്ചിടുക"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ അതിന് പുറത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"മനസ്സിലായി"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"കൂടുതൽ വിവരങ്ങൾക്ക് വികസിപ്പിക്കുക."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"റദ്ദാക്കുക"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"റീസ്റ്റാർട്ട് ചെയ്യൂ"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"വീണ്ടും കാണിക്കരുത്"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"ഈ ആപ്പ് നീക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യുക"</string> <string name="maximize_button_text" msgid="1650859196290301963">"വലുതാക്കുക"</string> <string name="minimize_button_text" msgid="271592547935841753">"ചെറുതാക്കുക"</string> <string name="close_button_text" msgid="2913281996024033299">"അടയ്ക്കുക"</string> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index c0c9eb7e247f..eccbc7e1d001 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Хэмжээг өөрчлөх"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Нуух"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ил гаргах"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Апп хуваагдсан дэлгэц дээр ажиллахгүй байж болзошгүй."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Энэ аппыг зөвхөн 1 цонхонд нээх боломжтой."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апп хоёрдогч дэлгэцэд ажиллахгүй."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Аппыг хоёрдогч дэлгэцэд эхлүүлэх боломжгүй."</string> - <string name="accessibility_divider" msgid="703810061635792791">"\"Дэлгэц хуваах\" хуваагч"</string> - <string name="divider_title" msgid="5482989479865361192">"\"Дэлгэцийг хуваах\" хуваагч"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Зүүн талын бүтэн дэлгэц"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Зүүн 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Зүүн 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Харж илүү ихийг хий"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Дэлгэцийг хуваахын тулд өөр апп руу чирнэ үү"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Аппыг дахин байрлуулахын тулд гадна талд нь хоёр товшино"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ойлголоо"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Нэмэлт мэдээлэл авах бол дэлгэнэ үү."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Цуцлах"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Дахин эхлүүлэх"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Дахиж бүү харуул"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Томруулах"</string> <string name="minimize_button_text" msgid="271592547935841753">"Багасгах"</string> <string name="close_button_text" msgid="2913281996024033299">"Хаах"</string> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index a18d1f1d9042..26cadf6ca5d1 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदला"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"स्टॅश करा"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्टॅश करा"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"अॅप कदाचित स्प्लिट स्क्रीनसह काम करू शकत नाही."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अॅप स्क्रीन-विभाजनास समर्थन देत नाही."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"हे अॅप फक्त एका विंडोमध्ये उघडले जाऊ शकते."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"दुसऱ्या डिस्प्लेवर अॅप कदाचित चालणार नाही."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"दुसऱ्या डिस्प्लेवर अॅप लाँच होणार नाही."</string> - <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रीन विभाजक"</string> - <string name="divider_title" msgid="5482989479865361192">"स्प्लिट-स्क्रीन विभाजक"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"डावी फुल स्क्रीन"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"डावी 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"डावी 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्यासाठी टॅप करा."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"पहा आणि आणखी बरेच काही करा"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट-स्क्रीन वापरण्यासाठी दुसऱ्या ॲपमध्ये ड्रॅग करा"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या बाहेर दोनदा टॅप करा"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"समजले"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"अधिक माहितीसाठी विस्तार करा."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"रद्द करा"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करा"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"पुन्हा दाखवू नका"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"हे ॲप हलवण्यासाठी दोनदा टॅप करा"</string> <string name="maximize_button_text" msgid="1650859196290301963">"मोठे करा"</string> <string name="minimize_button_text" msgid="271592547935841753">"लहान करा"</string> <string name="close_button_text" msgid="2913281996024033299">"बंद करा"</string> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index b891c5906ba4..32524320b1bc 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah saiz"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sembunyikan"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Tunjukkan"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Apl mungkin tidak berfungsi dengan skrin pisah."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Apl tidak menyokong skrin pisah."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Apl ini hanya boleh dibuka dalam 1 tetingkap."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Apl mungkin tidak berfungsi pada paparan kedua."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Apl tidak menyokong pelancaran pada paparan kedua."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Pembahagi skrin pisah"</string> - <string name="divider_title" msgid="5482989479865361192">"Pembahagi skrin pisah"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Skrin penuh kiri"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kiri 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Lihat dan lakukan lebih"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Seret apl lain untuk skrin pisah"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketik dua kali di luar apl untuk menempatkan semula apl itu"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kembangkan untuk mendapatkan maklumat lanjut."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Batal"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulakan semula"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Jangan tunjukkan lagi"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Ketik dua kali untuk mengalihkan apl ini"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimumkan"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimumkan"</string> <string name="close_button_text" msgid="2913281996024033299">"Tutup"</string> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 2b6adc16e85c..b7b2b87b1e55 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"အရွယ်အစားပြောင်းရန်"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"သိုဝှက်ရန်"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"မသိုဝှက်ရန်"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းဖြင့် အက်ပ်သည် အလုပ်မလုပ်ပါ။"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ဤအက်ပ်ကို ဝင်းဒိုး ၁ ခုတွင်သာ ဖွင့်နိုင်သည်။"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ဤအက်ပ်အနေဖြင့် ဖွင့်ရန်စနစ်ကို ဒုတိယဖန်သားပြင်မှ အသုံးပြုရန် ပံ့ပိုးမထားပါ။"</string> - <string name="accessibility_divider" msgid="703810061635792791">"မျက်နှာပြင်ခွဲခြမ်း ပိုင်းခြားပေးသည့်စနစ်"</string> - <string name="divider_title" msgid="5482989479865361192">"မျက်နှာပြင်ခွဲ၍ပြသသည့် စနစ်"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ဘယ်ဘက် မျက်နှာပြင်အပြည့်"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ဘယ်ဘက်မျက်နှာပြင် ၇၀%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ဘယ်ဘက် မျက်နှာပြင် ၅၀%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ကြည့်ပြီး ပိုမိုလုပ်ဆောင်ပါ"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"မျက်နှာပြင် ခွဲ၍ပြသနိုင်ရန် နောက်အက်ပ်တစ်ခုကို ဖိဆွဲပါ"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"နေရာပြန်ချရန် အက်ပ်အပြင်ဘက်ကို နှစ်ချက်တို့ပါ"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"နားလည်ပြီ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"နောက်ထပ်အချက်အလက်များအတွက် ချဲ့နိုင်သည်။"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"မလုပ်တော့"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ပြန်စရန်"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"နောက်ထပ်မပြပါနှင့်"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"ချဲ့ရန်"</string> <string name="minimize_button_text" msgid="271592547935841753">"ချုံ့ရန်"</string> <string name="close_button_text" msgid="2913281996024033299">"ပိတ်ရန်"</string> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index da5f4ca394b1..a184e8a7c72c 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Endre størrelse"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Oppbevar"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Avslutt oppbevaring"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Det kan hende at appen ikke fungerer med delt skjerm."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen støtter ikke delt skjerm."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denne appen kan bare åpnes i ett vindu."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer kanskje ikke på en sekundær skjerm."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke kjøres på sekundære skjermer."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Skilleelement for delt skjerm"</string> - <string name="divider_title" msgid="5482989479865361192">"Skilleelement for delt skjerm"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Utvid den venstre delen av skjermen til hele skjermen"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Sett størrelsen på den venstre delen av skjermen til 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sett størrelsen på den venstre delen av skjermen til 50 %"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flytt til nederst til høyre"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-innstillinger"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Lukk boblen"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Ikke vis bobler"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ikke vis samtaler i bobler"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat med bobler"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne en boble. Dra for å flytte den."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se og gjør mer"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dra inn en annen app for å bruke delt skjerm"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dobbelttrykk utenfor en app for å flytte den"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Greit"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vis for å få mer informasjon."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Avbryt"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Start på nytt"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ikke vis dette igjen"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimer"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string> <string name="close_button_text" msgid="2913281996024033299">"Lukk"</string> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 3afa9fbc624b..56e421f0e3b9 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदल्नुहोस्"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"स्ट्यास गर्नुहोस्"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्ट्यास गर्नुहोस्"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"एप विभाजित स्क्रिनमा काम नगर्न सक्छ।"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"यो एप एउटा विन्डोमा मात्र खोल्न मिल्छ।"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"अनुप्रयोगले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string> - <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रिन छुट्याउने"</string> - <string name="divider_title" msgid="5482989479865361192">"स्प्लिट स्क्रिन डिभाइडर"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बायाँ भाग फुल स्क्रिन"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"बायाँ भाग ७०%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बायाँ भाग ५०%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"थप कुरा हेर्नुहोस् र गर्नुहोस्"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"स्प्लिट स्क्रिन मोड प्रयोग गर्न अर्को एप ड्रयाग एन्ड ड्रप गर्नुहोस्"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको बाहिर डबल ट्याप गर्नुहोस्"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"बुझेँ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"थप जानकारी प्राप्त गर्न चाहनुहुन्छ भने एक्स्पान्ड गर्नुहोस्।"</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"रद्द गर्नुहोस्"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"रिस्टार्ट गर्नुहोस्"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फेरि नदेखाइयोस्"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"यो एप सार्न डबल ट्याप गर्नुहोस्"</string> <string name="maximize_button_text" msgid="1650859196290301963">"ठुलो बनाउनुहोस्"</string> <string name="minimize_button_text" msgid="271592547935841753">"मिनिमाइज गर्नुहोस्"</string> <string name="close_button_text" msgid="2913281996024033299">"बन्द गर्नुहोस्"</string> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index 21e89c3666b3..6347ee6df5d6 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Formaat aanpassen"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Verbergen"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Niet meer verbergen"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"De app werkt mogelijk niet met gesplitst scherm."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App biedt geen ondersteuning voor gesplitst scherm."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Deze app kan slechts in 1 venster worden geopend."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App werkt mogelijk niet op een secundair scherm."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App kan niet op secundaire displays worden gestart."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Scheiding voor gesplitst scherm"</string> - <string name="divider_title" msgid="5482989479865361192">"Scheiding voor gesplitst scherm"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Linkerscherm op volledig scherm"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Linkerscherm 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Linkerscherm 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zie en doe meer"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Sleep een andere app hier naartoe om het scherm te splitsen"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik naast een app om deze opnieuw te positioneren"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Uitvouwen voor meer informatie."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuleren"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Opnieuw opstarten"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Niet opnieuw tonen"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dubbeltik om deze app te verplaatsen"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximaliseren"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimaliseren"</string> <string name="close_button_text" msgid="2913281996024033299">"Sluiten"</string> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index e781f4522efb..f302bf51c180 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ରିସାଇଜ୍ କରନ୍ତୁ"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ଲୁଚାନ୍ତୁ"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ଦେଖାନ୍ତୁ"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରିନରେ ଆପ୍ କାମ କରିନପାରେ।"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ଆପ୍ ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରୀନକୁ ସପୋର୍ଟ କରେ ନାହିଁ।"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ଏହି ଆପକୁ କେବଳ 1ଟି ୱିଣ୍ଡୋରେ ଖୋଲାଯାଇପାରିବ।"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍ କାମ ନକରିପାରେ।"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍ ଲଞ୍ଚ ସପୋର୍ଟ କରେ ନାହିଁ।"</string> - <string name="accessibility_divider" msgid="703810061635792791">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରୀନ ବିଭାଜକ"</string> - <string name="divider_title" msgid="5482989479865361192">"ସ୍ପ୍ଲିଟ-ସ୍କ୍ରିନ ଡିଭାଇଡର"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ବାମ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍ କରନ୍ତୁ"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ବାମ ପଟକୁ 70% କରନ୍ତୁ"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ବାମ ପଟକୁ 50% କରନ୍ତୁ"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ଦେଖନ୍ତୁ ଏବଂ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ସ୍ପ୍ଲିଟ-ସ୍କ୍ରିନ ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହାର ବାହାରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ବୁଝିଗଲି"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ଅଧିକ ସୂଚନା ପାଇଁ ବିସ୍ତାର କରନ୍ତୁ।"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ବାତିଲ କରନ୍ତୁ"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"ବଡ଼ କରନ୍ତୁ"</string> <string name="minimize_button_text" msgid="271592547935841753">"ଛୋଟ କରନ୍ତୁ"</string> <string name="close_button_text" msgid="2913281996024033299">"ବନ୍ଦ କରନ୍ତୁ"</string> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index d39fe95fdc50..eb32e25c7d08 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ਆਕਾਰ ਬਦਲੋ"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ਸਟੈਸ਼"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ਅਣਸਟੈਸ਼"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ਇਹ ਐਪ ਸਿਰਫ਼ 1 ਵਿੰਡੋ ਵਿੱਚ ਖੋਲ੍ਹੀ ਜਾ ਸਕਦੀ ਹੈ।"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇਆਂ \'ਤੇ ਲਾਂਚ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string> - <string name="accessibility_divider" msgid="703810061635792791">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਡਿਵਾਈਡਰ"</string> - <string name="divider_title" msgid="5482989479865361192">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਵਿਭਾਜਕ"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ਖੱਬੇ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ਖੱਬੇ 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ਖੱਬੇ 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ਸੈਟਿੰਗਾਂ"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"ਬਬਲ ਨਾ ਕਰੋ"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ਦੇਖੋ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਕਰੋ"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੇ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਵਿੱਚ ਘਸੀਟੋ"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਬਾਹਰ ਡਬਲ ਟੈਪ ਕਰੋ"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ਸਮਝ ਲਿਆ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਵਿਸਤਾਰ ਕਰੋ।"</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ਰੱਦ ਕਰੋ"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"ਵੱਡਾ ਕਰੋ"</string> <string name="minimize_button_text" msgid="271592547935841753">"ਛੋਟਾ ਕਰੋ"</string> <string name="close_button_text" msgid="2913281996024033299">"ਬੰਦ ਕਰੋ"</string> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index ef7773b9ca31..d61cbf549a10 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmień rozmiar"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Przenieś do schowka"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zabierz ze schowka"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacja może nie działać przy podzielonym ekranie."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacja nie obsługuje dzielonego ekranu."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ta aplikacja może być otwarta tylko w 1 oknie."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacja może nie działać na dodatkowym ekranie."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacja nie obsługuje uruchamiania na dodatkowych ekranach."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Linia dzielenia ekranu"</string> - <string name="divider_title" msgid="5482989479865361192">"Linia dzielenia ekranu"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lewa część ekranu na pełnym ekranie"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% lewej części ekranu"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% lewej części ekranu"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobacz i zrób więcej"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Przeciągnij drugą aplikację, aby podzielić ekran"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kliknij dwukrotnie poza aplikacją, aby ją przenieść"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozwiń, aby wyświetlić więcej informacji."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anuluj"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Uruchom ponownie"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nie pokazuj ponownie"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Kliknij dwukrotnie, aby przenieść tę aplikację"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksymalizuj"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimalizuj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zamknij"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index b034990ee845..c431100b2901 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ocultar"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Este app só pode ser aberto em uma única janela."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string> - <string name="divider_title" msgid="5482989479865361192">"Divisor de tela"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lado esquerdo em tela cheia"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Esquerda a 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outro app para a tela dividida"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Toque duas vezes para mover o app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index c739ba07020f..a8dbb808c073 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Armazenar"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Remover do armazenamento"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"A app pode não funcionar com o ecrã dividido."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A app não é compatível com o ecrã dividido."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta app só pode ser aberta em 1 janela."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"A app pode não funcionar num ecrã secundário."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A app não é compatível com o início em ecrãs secundários."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Divisor do ecrã dividido"</string> - <string name="divider_title" msgid="5482989479865361192">"Divisor do ecrã dividido"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ecrã esquerdo inteiro"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% no ecrã esquerdo"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% no ecrã esquerdo"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outra app para usar o ecrã dividido"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de uma app para a reposicionar"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expandir para obter mais informações"</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar de novo"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Toque duas vezes para mover esta app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index b034990ee845..c431100b2901 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ocultar"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Este app só pode ser aberto em uma única janela."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string> - <string name="divider_title" msgid="5482989479865361192">"Divisor de tela"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lado esquerdo em tela cheia"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Esquerda a 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Arraste outro app para a tela dividida"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Toque duas vezes para mover o app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index cbe11dd9ac45..15682687459b 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionează"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stochează"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulează stocarea"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aplicația poate fi deschisă într-o singură fereastră."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Este posibil ca aplicația să nu funcționeze pe un ecran secundar."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplicația nu acceptă lansare pe ecrane secundare."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Separator pentru ecranul împărțit"</string> - <string name="divider_title" msgid="5482989479865361192">"Separator pentru ecranul împărțit"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Partea stângă pe ecran complet"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Partea stângă: 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Partea stângă: 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ai remediat problema?\nAtinge pentru a reveni"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu ai probleme cu camera foto? Atinge pentru a închide."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vezi și fă mai multe"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Atinge de două ori lângă o aplicație pentru a o repoziționa"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extinde pentru mai multe informații"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anulează"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Repornește"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nu mai afișa"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Maximizează"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizează"</string> <string name="close_button_text" msgid="2913281996024033299">"Închide"</string> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index 7602282a94a5..83934c476fae 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Изменить размер"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Скрыть"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показать"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"В режиме разделения экрана приложение может работать нестабильно."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложение не поддерживает разделение экрана."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Это приложение можно открыть только в одном окне."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Приложение может не работать на дополнительном экране"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложение не поддерживает запуск на дополнительных экранах"</string> - <string name="accessibility_divider" msgid="703810061635792791">"Разделитель экрана"</string> - <string name="divider_title" msgid="5482989479865361192">"Разделитель экрана"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левый во весь экран"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левый на 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левый на 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Выполняйте несколько задач одновременно"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Перетащите сюда другое приложение, чтобы использовать разделение экрана."</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Чтобы переместить приложение, дважды нажмите рядом с ним."</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ОК"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Развернуть, чтобы узнать больше."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Отмена"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустить"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больше не показывать"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Нажмите дважды, чтобы переместить приложение."</string> <string name="maximize_button_text" msgid="1650859196290301963">"Развернуть"</string> <string name="minimize_button_text" msgid="271592547935841753">"Свернуть"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрыть"</string> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index 680f1388247a..21ae496903c5 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ප්රතිප්රමාණ කරන්න"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"සඟවා තබන්න"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"සඟවා තැබීම ඉවත් කරන්න"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"යෙදුම බෙදුම් තිරය සමග ක්රියා නොකළ හැකිය"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"මෙම යෙදුම විවෘත කළ හැක්කේ 1 කවුළුවක පමණයි."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"යෙදුම ද්විතියික සංදර්ශකයක ක්රියා නොකළ හැකිය."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"යෙදුම ද්විතීයික සංදර්ශක මත දියත් කිරීම සඳහා සහාය නොදක්වයි."</string> - <string name="accessibility_divider" msgid="703810061635792791">"බෙදුම්-තිර වෙන්කරණය"</string> - <string name="divider_title" msgid="5482989479865361192">"බෙදුම්-තිර වෙන්කරණය"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"වම් පූර්ණ තිරය"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"වම් 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"වම් 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"පහළ දකුණට ගෙන යන්න"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> සැකසීම්"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"බුබුලු ඉවත ලන්න"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"බුබුළු නොකරන්න"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"සංවාදය බුබුලු නොදමන්න"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"නව සංවාද පාවෙන අයිකන හෝ බුබුලු ලෙස දිස් වේ. බුබුල විවෘත කිරීමට තට්ටු කරන්න. එය ගෙන යාමට අදින්න."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්රතිවර්තනය කිරීමට තට්ටු කරන්න"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"බලන්න සහ තවත් දේ කරන්න"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"බෙදුම් තිරය සඳහා වෙනත් යෙදුමකට අදින්න"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"යෙදුමක් නැවත ස්ථානගත කිරීමට පිටතින් දෙවරක් තට්ටු කරන්න"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"තේරුණා"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"වැඩිදුර තොරතුරු සඳහා දිග හරින්න"</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"අවලංගු කරන්න"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"යළි අරඹන්න"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"නැවත නොපෙන්වන්න"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"විහිදන්න"</string> <string name="minimize_button_text" msgid="271592547935841753">"කුඩා කරන්න"</string> <string name="close_button_text" msgid="2913281996024033299">"වසන්න"</string> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index c9081848e31e..fb43ba88dfd8 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmeniť veľkosť"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skryť"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušiť skrytie"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikácia nemusí fungovať s rozdelenou obrazovkou."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikácia nepodporuje rozdelenú obrazovku."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Táto aplikácia môže byť otvorená iba v jednom okne."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikácia nemusí fungovať na sekundárnej obrazovke."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikácia nepodporuje spúšťanie na sekundárnych obrazovkách."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Rozdeľovač obrazovky"</string> - <string name="divider_title" msgid="5482989479865361192">"Rozdeľovač obrazovky"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ľavá – na celú obrazovku"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ľavá – 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ľavá – 50 %"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobrazte si a zvládnite toho viac"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Rozdelenú obrazovku aktivujete presunutím ďalšie aplikácie"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikácie zmeníte jej pozíciu"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Dobre"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Po rozbalení sa dozviete viac."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Zrušiť"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reštartovať"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Už nezobrazovať"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Túto aplikáciu presuniete dvojitým klepnutím"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovať"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimalizovať"</string> <string name="close_button_text" msgid="2913281996024033299">"Zavrieť"</string> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index ed7feb936b7c..331b3fd0d375 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Spremeni velikost"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Zakrij"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Razkrij"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podpira načina razdeljenega zaslona."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"To aplikacijo je mogoče odpreti samo v enem oknu."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija morda ne bo delovala na sekundarnem zaslonu."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podpira zagona na sekundarnih zaslonih."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Razdelilnik zaslonov"</string> - <string name="divider_title" msgid="5482989479865361192">"Razdelilnik zaslonov"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Levi v celozaslonski način"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Levi 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi 50 %"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Oglejte si in naredite več"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Za razdeljeni zaslon povlecite sem še eno aplikacijo."</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvakrat se dotaknite zunaj aplikacije, če jo želite prestaviti."</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"V redu"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Razširitev za več informacij"</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Prekliči"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Znova zaženi"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikaži več"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dvakrat se dotaknite, če želite premakniti to aplikacijo"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiraj"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimiraj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zapri"</string> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index 0b64d5d13d40..c7a1d9cec212 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ndrysho përmasat"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Fshih"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Mos e fshih"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacioni mund të mos funksionojë me ekranin e ndarë."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacioni nuk mbështet ekranin e ndarë."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ky aplikacion mund të hapet vetëm në 1 dritare."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacioni mund të mos funksionojë në një ekran dytësor."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacioni nuk mbështet nisjen në ekrane dytësore."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Ndarësi i ekranit të ndarë"</string> - <string name="divider_title" msgid="5482989479865361192">"Ndarësi i ekranit të ndarë"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ekrani i plotë majtas"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Majtas 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Majtas 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Shiko dhe bëj më shumë"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Zvarrite në një aplikacion tjetër për ekranin e ndarë"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Trokit dy herë jashtë një aplikacioni për ta ripozicionuar"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Zgjeroje për më shumë informacion."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anulo"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Rinis"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Mos e shfaq përsëri"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Trokit dy herë për ta lëvizur këtë aplikacion"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Maksimizo"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizo"</string> <string name="close_button_text" msgid="2913281996024033299">"Mbyll"</string> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index 8f44eeb83a2e..c4ea1f7a912e 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промените величину"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ставите у тајну меморију"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Уклоните из тајне меморије"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликација можда неће радити са подељеним екраном."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликација не подржава подељени екран."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ова апликација може да се отвори само у једном прозору."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликација можда неће функционисати на секундарном екрану."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликација не подржава покретање на секундарним екранима."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Разделник подељеног екрана"</string> - <string name="divider_title" msgid="5482989479865361192">"Разделник подељеног екрана"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Режим целог екрана за леви екран"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Леви екран 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Леви екран 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Видите и урадите више"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Превуците другу апликацију да бисте користили подељени екран"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двапут додирните изван апликације да бисте променили њену позицију"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширите за још информација."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Откажи"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартуј"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не приказуј поново"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Двапут додирните да бисте преместили ову апликацију"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Увећајте"</string> <string name="minimize_button_text" msgid="271592547935841753">"Умањите"</string> <string name="close_button_text" msgid="2913281996024033299">"Затворите"</string> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index 1bd744a27d00..5ae673a3340f 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ändra storlek"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Utför stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Återställ stash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen kanske inte fungerar med delad skärm."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen har inte stöd för delad skärm."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denna app kan bara vara öppen i ett fönster."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen kanske inte fungerar på en sekundär skärm."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan inte köras på en sekundär skärm."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Avdelare för delad skärm"</string> - <string name="divider_title" msgid="5482989479865361192">"Avdelare för delad skärm"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Helskärm på vänster skärm"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vänster 70 %"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vänster 50 %"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Se och gör mer"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Dra till en annan app för läget Delad skärm"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryck snabbt två gånger utanför en app för att flytta den"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Utöka för mer information."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Avbryt"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Starta om"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Visa inte igen"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Utöka"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimera"</string> <string name="close_button_text" msgid="2913281996024033299">"Stäng"</string> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index f2f3bbc99bf8..9c79b3bc663a 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Badilisha ukubwa"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ficha"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Fichua"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Huenda programu isifanye kazi kwenye skrini inayogawanywa."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programu haiwezi kutumia skrini iliyogawanywa."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Programu hii inaweza kufunguliwa katika dirisha 1 pekee."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Huenda programu isifanye kazi kwenye dirisha lingine."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programu hii haiwezi kufunguliwa kwenye madirisha mengine."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Kitenganishi cha skrini inayogawanywa"</string> - <string name="divider_title" msgid="5482989479865361192">"Kitenganishi cha kugawa skrini"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Skrini nzima ya kushoto"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kushoto 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kushoto 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Angalia na ufanye zaidi"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Buruta ndani programu nyingine ili utumie hali ya skrini iliyogawanywa"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Gusa mara mbili nje ya programu ili uihamishe"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Nimeelewa"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Panua ili upate maelezo zaidi."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Ghairi"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Zima kisha uwashe"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Usionyeshe tena"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Gusa mara mbili ili usogeze programu hii"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Panua"</string> <string name="minimize_button_text" msgid="271592547935841753">"Punguza"</string> <string name="close_button_text" msgid="2913281996024033299">"Funga"</string> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index 10f040b0c682..3b9c9f3630ba 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"அளவு மாற்று"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"திரைப் பிரிப்பு அம்சத்தில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"திரையைப் பிரிப்பதைப் ஆப்ஸ் ஆதரிக்கவில்லை."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"இந்த ஆப்ஸை 1 சாளரத்தில் மட்டுமே திறக்க முடியும்."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"இரண்டாம்நிலைத் திரைகளில் பயன்பாட்டைத் தொடங்க முடியாது."</string> - <string name="accessibility_divider" msgid="703810061635792791">"திரையைப் பிரிக்கும் பிரிப்பான்"</string> - <string name="divider_title" msgid="5482989479865361192">"திரைப் பிரிப்பான்"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"இடது புறம் முழுத் திரை"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"இடது புறம் 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"இடது புறம் 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"கீழே வலதுபுறமாக நகர்த்து"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> அமைப்புகள்"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"குமிழை அகற்று"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"குமிழ்களைக் காட்ட வேண்டாம்"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"உரையாடலைக் குமிழாக்காதே"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"பலவற்றைப் பார்த்தல் மற்றும் செய்தல்"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"திரைப் பிரிப்புக்கு மற்றொரு ஆப்ஸை இழுக்கலாம்"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ஆப்ஸை இடம் மாற்ற அதன் வெளியில் இருமுறை தட்டலாம்"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"சரி"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"கூடுதல் தகவல்களுக்கு விரிவாக்கலாம்."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ரத்துசெய்"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"மீண்டும் தொடங்கு"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"மீண்டும் காட்டாதே"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"பெரிதாக்கும்"</string> <string name="minimize_button_text" msgid="271592547935841753">"சிறிதாக்கும்"</string> <string name="close_button_text" msgid="2913281996024033299">"மூடும்"</string> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index 581a5abeeee9..2b0725c93694 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"సైజ్ మార్చు"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్స్టాచ్"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్ పని చేయకపోవచ్చు."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"యాప్లో స్క్రీన్ విభజనకు మద్దతు లేదు."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ఈ యాప్ను 1 విండోలో మాత్రమే తెరవవచ్చు."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్ప్లేలో యాప్ పని చేయకపోవచ్చు."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ప్రత్యామ్నాయ డిస్ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు."</string> - <string name="accessibility_divider" msgid="703810061635792791">"విభజన స్క్రీన్ విభాగిని"</string> - <string name="divider_title" msgid="5482989479865361192">"స్ప్లిట్ స్క్రీన్ డివైడర్"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ఎడమవైపు ఫుల్-స్క్రీన్"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ఎడమవైపు 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ఎడమవైపు 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"చూసి, మరిన్ని చేయండి"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"స్ప్లిట్-స్క్రీన్ కోసం మరొక యాప్లోకి లాగండి"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"యాప్ స్థానాన్ని మార్చడానికి దాని వెలుపల డబుల్-ట్యాప్ చేయండి"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"మరింత సమాచారం కోసం విస్తరించండి."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"రద్దు చేయండి"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"రీస్టార్ట్ చేయండి"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"మళ్లీ చూపవద్దు"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"ఈ యాప్ను తరలించడానికి డబుల్-ట్యాప్ చేయండి"</string> <string name="maximize_button_text" msgid="1650859196290301963">"గరిష్టీకరించండి"</string> <string name="minimize_button_text" msgid="271592547935841753">"కుదించండి"</string> <string name="close_button_text" msgid="2913281996024033299">"మూసివేయండి"</string> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index 44afb58e7ada..a9b8086f4c73 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ปรับขนาด"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"เก็บเข้าที่เก็บส่วนตัว"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"เอาออกจากที่เก็บส่วนตัว"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"แอปอาจใช้ไม่ได้กับโหมดแบ่งหน้าจอ"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"แอปไม่สนับสนุนการแยกหน้าจอ"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"แอปนี้เปิดได้ใน 1 หน้าต่างเท่านั้น"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"แอปอาจไม่ทำงานในจอแสดงผลรอง"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"แอปไม่รองรับการเรียกใช้ในจอแสดงผลรอง"</string> - <string name="accessibility_divider" msgid="703810061635792791">"เส้นแบ่งหน้าจอ"</string> - <string name="divider_title" msgid="5482989479865361192">"เส้นแยกหน้าจอ"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"เต็มหน้าจอทางซ้าย"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ซ้าย 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ซ้าย 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"รับชมและทำสิ่งต่างๆ ได้มากขึ้น"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"ลากไปไว้ในแอปอื่นเพื่อแยกหน้าจอ"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"แตะสองครั้งด้านนอกแอปเพื่อเปลี่ยนตำแหน่ง"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"รับทราบ"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ขยายเพื่อดูข้อมูลเพิ่มเติม"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ยกเลิก"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"รีสตาร์ท"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ไม่ต้องแสดงข้อความนี้อีก"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"ขยายใหญ่สุด"</string> <string name="minimize_button_text" msgid="271592547935841753">"ย่อ"</string> <string name="close_button_text" msgid="2913281996024033299">"ปิด"</string> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index d287e9d81d96..9cf3576aae74 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"I-resize"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"I-stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"I-unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Posibleng hindi gumana ang app sa split screen."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Hindi sinusuportahan ng app ang split-screen."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Sa 1 window lang puwedeng buksan ang app na ito."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Maaaring hindi gumana ang app sa pangalawang display."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Hindi sinusuportahan ng app ang paglulunsad sa mga pangalawang display."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Divider ng split-screen"</string> - <string name="divider_title" msgid="5482989479865361192">"Divider ng split-screen"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"I-full screen ang nasa kaliwa"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Gawing 70% ang nasa kaliwa"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Gawing 50% ang nasa kaliwa"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Tumingin at gumawa ng higit pa"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Mag-drag ng ibang app para sa split screen"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Mag-double tap sa labas ng app para baguhin ang posisyon nito"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"I-expand para sa higit pang impormasyon."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Kanselahin"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"I-restart"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Huwag nang ipakita ulit"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"I-double tap para ilipat ang app na ito"</string> <string name="maximize_button_text" msgid="1650859196290301963">"I-maximize"</string> <string name="minimize_button_text" msgid="271592547935841753">"I-minimize"</string> <string name="close_button_text" msgid="2913281996024033299">"Isara"</string> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 969e4030be22..4e398e57d558 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Yeniden boyutlandır"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Depola"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Depolama"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Uygulama bölünmüş ekranda çalışmayabilir."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uygulama bölünmüş ekranı desteklemiyor."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu uygulama yalnızca 1 pencerede açılabilir."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uygulama ikincil ekranda çalışmayabilir."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uygulama ikincil ekranlarda başlatılmayı desteklemiyor."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcı"</string> - <string name="divider_title" msgid="5482989479865361192">"Bölünmüş ekran ayırıcı"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Solda tam ekran"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Solda %70"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Solda %50"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sağ alta taşı"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ayarları"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Baloncuğu kapat"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Bildirim baloncuğu gösterme"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Görüşmeyi baloncuk olarak görüntüleme"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Baloncukları kullanarak sohbet edin"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Daha fazlasını görün ve yapın"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Bölünmüş ekran için başka bir uygulamayı sürükleyin"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Yeniden konumlandırmak için uygulamanın dışına iki kez dokunun"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Daha fazla bilgi için genişletin."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"İptal"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Yeniden başlat"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Bir daha gösterme"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Ekranı Kapla"</string> <string name="minimize_button_text" msgid="271592547935841753">"Küçült"</string> <string name="close_button_text" msgid="2913281996024033299">"Kapat"</string> diff --git a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml index 0b61d7a85d9e..adbf65648dd1 100644 --- a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml +++ b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml @@ -36,7 +36,9 @@ <dimen name="pip_menu_arrow_size">24dp</dimen> <dimen name="pip_menu_arrow_elevation">5dp</dimen> - <dimen name="pip_menu_elevation">1dp</dimen> + <dimen name="pip_menu_elevation_no_menu">1dp</dimen> + <dimen name="pip_menu_elevation_move_menu">7dp</dimen> + <dimen name="pip_menu_elevation_all_actions_menu">4dp</dimen> <dimen name="pip_menu_edu_text_view_height">24dp</dimen> <dimen name="pip_menu_edu_text_home_icon">9sp</dimen> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index e265e2f0f54b..4ccb0bcbaf07 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змінити розмір"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сховати"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показати"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Додаток може не працювати в режимі розділеного екрана."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Додаток не підтримує розділення екрана."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Цей додаток можна відкрити лише в одному вікні."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Додаток може не працювати на додатковому екрані."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Додаток не підтримує запуск на додаткових екранах."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Розділювач екрана"</string> - <string name="divider_title" msgid="5482989479865361192">"Розділювач екрана"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ліве вікно на весь екран"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ліве вікно на 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ліве вікно на 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перемістити праворуч униз"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Налаштування параметра \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"Закрити підказку"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"Не показувати спливаючі чати"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не показувати спливаючі чати для розмов"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Спливаючий чат"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Більше простору та можливостей"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Щоб перейти в режим розділення екрана, перетягніть сюди інший додаток"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Щоб перемістити додаток, двічі торкніться області поза ним"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"ОK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Розгорніть, щоб дізнатися більше."</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Скасувати"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустити"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Більше не показувати"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Збільшити"</string> <string name="minimize_button_text" msgid="271592547935841753">"Згорнути"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрити"</string> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index 5599351e323a..4aef27c45895 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"سائز تبدیل کریں"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن ہے کہ ایپ اسپلٹ اسکرین کے ساتھ کام نہ کرے۔"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"یہ ایپ صرف 1 ونڈو میں کھولی جا سکتی ہے۔"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن ہے ایپ ثانوی ڈسپلے پر کام نہ کرے۔"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ایپ ثانوی ڈسپلیز پر شروعات کا تعاون نہیں کرتی۔"</string> - <string name="accessibility_divider" msgid="703810061635792791">"سپلٹ اسکرین تقسیم کار"</string> - <string name="divider_title" msgid="5482989479865361192">"اسپلٹ اسکرین ڈیوائیڈر"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"بائیں فل اسکرین"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"بائیں %70"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"بائیں %50"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"دیکھیں اور بہت کچھ کریں"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"اسپلٹ اسکرین کے ليے دوسری ایپ میں گھسیٹیں"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس ایپ کے باہر دو بار تھپتھپائیں"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"سمجھ آ گئی"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"مزید معلومات کے لیے پھیلائیں۔"</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"منسوخ کریں"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"ری اسٹارٹ کریں"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوبارہ نہ دکھائیں"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"اس ایپ کو منتقل کرنے کیلئے دو بار تھپتھپائیں"</string> <string name="maximize_button_text" msgid="1650859196290301963">"بڑا کریں"</string> <string name="minimize_button_text" msgid="271592547935841753">"چھوٹا کریں"</string> <string name="close_button_text" msgid="2913281996024033299">"بند کریں"</string> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index 548981568342..04cc7ee24abc 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Oʻlchamini oʻzgartirish"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Berkitish"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Chiqarish"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Bu ilova ekranni ikkiga ajratish rejimini dastaklamaydi."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu ilovani faqat 1 ta oynada ochish mumkin."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Bu ilova qo‘shimcha ekranda ishlamasligi mumkin."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Bu ilova qo‘shimcha ekranlarda ishga tushmaydi."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Ekranni ikkiga bo‘lish chizig‘i"</string> - <string name="divider_title" msgid="5482989479865361192">"Ekranni ikkiga ajratish chizigʻi"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Chapda to‘liq ekran"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Chapda 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Chapda 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Yana boshqa amallar"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Ekranni ikkiga ajratish uchun boshqa ilovani bu yerga torting"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Qayta joylash uchun ilova tashqarisiga ikki marta bosing"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Batafsil axborot olish uchun kengaytiring."</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Bekor qilish"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Qaytadan"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Boshqa chiqmasin"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Bu ilovaga olish uchun ikki marta bosing"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Yoyish"</string> <string name="minimize_button_text" msgid="271592547935841753">"Kichraytirish"</string> <string name="close_button_text" msgid="2913281996024033299">"Yopish"</string> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index bb144a7f5992..a207471b4f1b 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Đổi kích thước"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ẩn"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Hiện"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Ứng dụng có thể không hoạt động với tính năng chia đôi màn hình."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Ứng dụng không hỗ trợ chia đôi màn hình."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ứng dụng này chỉ có thể mở 1 cửa sổ."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Bộ chia chia đôi màn hình"</string> - <string name="divider_title" msgid="5482989479865361192">"Bộ chia màn hình"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Toàn màn hình bên trái"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Trái 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Trái 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Xem và làm được nhiều việc hơn"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Kéo vào một ứng dụng khác để chia đôi màn hình"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Nhấn đúp bên ngoài ứng dụng để đặt lại vị trí"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mở rộng để xem thêm thông tin."</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Huỷ"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Khởi động lại"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Không hiện lại"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"Phóng to"</string> <string name="minimize_button_text" msgid="271592547935841753">"Thu nhỏ"</string> <string name="close_button_text" msgid="2913281996024033299">"Đóng"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 4b2ee183c8d7..f291bf3eb4d5 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"调整大小"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"隐藏"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消隐藏"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"应用可能无法在分屏模式下正常运行。"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"应用不支持分屏。"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"此应用只能在 1 个窗口中打开。"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"应用可能无法在辅显示屏上正常运行。"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"应用不支持在辅显示屏上启动。"</string> - <string name="accessibility_divider" msgid="703810061635792791">"分屏分隔线"</string> - <string name="divider_title" msgid="5482989479865361192">"分屏分隔线"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左侧全屏"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左侧 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左侧 50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"查看和处理更多任务"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖入另一个应用,即可使用分屏模式"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在某个应用外连续点按两次,即可调整它的位置"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展开即可了解详情。"</string> @@ -94,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"取消"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"重启"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不再显示"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string> <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"关闭"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index 7a2d3485245c..ade02ba983ce 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"保護"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消保護"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"應用程式不支援分割畫面。"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"此應用程式只可在 1 個視窗中開啟"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示屏上運作。"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示屏上啟動。"</string> - <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string> - <string name="divider_title" msgid="5482989479865361192">"分割螢幕分隔線"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左邊全螢幕"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左邊 70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左邊 50%"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移去右下角"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"關閉小視窗氣泡"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"不要顯示對話氣泡"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要透過小視窗顯示對話"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"使用小視窗進行即時通訊"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"新對話會以浮動圖示 (小視窗) 顯示。輕按即可開啟小視窗。拖曳即可移動小視窗。"</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖入另一個應用程式即可分割螢幕"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕按兩下即可調整位置"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳情。"</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"取消"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string> <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"關閉"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index b0ccd8a82905..a9b3beb84027 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"暫時隱藏"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消暫時隱藏"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"這個應用程式不支援分割畫面。"</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"這個應用程式只能在 1 個視窗中開啟。"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示器上運作。"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示器上啟動。"</string> - <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string> - <string name="divider_title" msgid="5482989479865361192">"分割畫面分隔線"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"以全螢幕顯示左側畫面"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"以 70% 的螢幕空間顯示左側畫面"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"以 50% 的螢幕空間顯示左側畫面"</string> @@ -68,8 +72,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移至右下方"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</string> <string name="bubble_dismiss_text" msgid="8816558050659478158">"關閉對話框"</string> - <!-- no translation found for bubbles_dont_bubble (3216183855437329223) --> - <skip /> + <string name="bubbles_dont_bubble" msgid="3216183855437329223">"不要顯示對話框"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要以對話框形式顯示對話"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"透過對話框來聊天"</string> <string name="bubbles_user_education_description" msgid="4215862563054175407">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string> @@ -86,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"拖進另一個應用程式即可使用分割畫面模式"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕觸兩下即可調整位置"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"我知道了"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳細資訊。"</string> @@ -95,6 +99,8 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"取消"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string> + <!-- no translation found for letterbox_reachability_reposition_text (4507890186297500893) --> + <skip /> <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string> <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"關閉"</string> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index 1a6e46c60170..12a4703656e5 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -32,13 +32,17 @@ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Shintsha usayizi"</string> <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Yenza isiteshi"</string> <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Susa isiteshi"</string> - <string name="dock_forced_resizable" msgid="1749750436092293116">"Izinhlelo zokusebenza kungenzeka zingasebenzi ngesikrini esihlukanisiwe."</string> - <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string> + <!-- no translation found for dock_forced_resizable (7429086980048964687) --> + <skip /> + <!-- no translation found for dock_non_resizeble_failed_to_dock_text (2733543750291266047) --> + <skip /> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Le-app ingavulwa kuphela ewindini eli-1."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uhlelo lokusebenza kungenzeka lungasebenzi kusibonisi sesibili."</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uhlelo lokusebenza alusekeli ukuqalisa kuzibonisi zesibili."</string> - <string name="accessibility_divider" msgid="703810061635792791">"Isihlukanisi sokuhlukanisa isikrini"</string> - <string name="divider_title" msgid="5482989479865361192">"Isihlukanisi sokuhlukanisa isikrini"</string> + <!-- no translation found for accessibility_divider (6407584574218956849) --> + <skip /> + <!-- no translation found for divider_title (1963391955593749442) --> + <skip /> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Isikrini esigcwele esingakwesokunxele"</string> <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kwesokunxele ngo-70%"</string> <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kwesokunxele ngo-50%"</string> @@ -85,7 +89,8 @@ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string> <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string> <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Bona futhi wenze okuningi"</string> - <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Hudula kwenye i-app mayelana nokuhlukanisa isikrini"</string> + <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> + <skip /> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Thepha kabili ngaphandle kwe-app ukuze uyimise kabusha"</string> <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ngiyezwa"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Nweba ukuze uthole ulwazi olwengeziwe"</string> @@ -94,6 +99,7 @@ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Khansela"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Qala kabusha"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ungabonisi futhi"</string> + <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Thepha kabili ukuze uhambise le-app"</string> <string name="maximize_button_text" msgid="1650859196290301963">"Khulisa"</string> <string name="minimize_button_text" msgid="271592547935841753">"Nciphisa"</string> <string name="close_button_text" msgid="2913281996024033299">"Vala"</string> diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index 4a1635d71c57..4b885c278a7a 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -67,4 +67,7 @@ <color name="desktop_mode_caption_close_button_dark">#1C1C17</color> <color name="desktop_mode_caption_app_name_light">#EFF1F2</color> <color name="desktop_mode_caption_app_name_dark">#1C1C17</color> + <color name="desktop_mode_caption_menu_text_color">#191C1D</color> + <color name="desktop_mode_caption_menu_buttons_color_inactive">#191C1D</color> + <color name="desktop_mode_caption_menu_buttons_color_active">#00677E</color> </resources> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index c98a056c5986..9049ed574ba5 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -226,6 +226,8 @@ <dimen name="bubble_user_education_padding_end">58dp</dimen> <!-- Padding between the bubble and the user education text. --> <dimen name="bubble_user_education_stack_padding">16dp</dimen> + <!-- Size of the bubble bar (height), should match transient_taskbar_size in Launcher. --> + <dimen name="bubblebar_size">72dp</dimen> <!-- Bottom and end margin for compat buttons. --> <dimen name="compat_button_margin">24dp</dimen> @@ -370,20 +372,34 @@ <!-- Height of button (32dp) + 2 * margin (5dp each). --> <dimen name="freeform_decor_caption_height">42dp</dimen> - <!-- Width of buttons (32dp each) + padding (128dp total). --> - <dimen name="freeform_decor_caption_menu_width">256dp</dimen> + <!-- The width of the handle menu in desktop mode. --> + <dimen name="desktop_mode_handle_menu_width">216dp</dimen> - <dimen name="freeform_decor_caption_menu_height">250dp</dimen> - <dimen name="freeform_decor_caption_menu_height_no_windowing_controls">210dp</dimen> + <!-- The height of the handle menu's "App Info" pill in desktop mode. --> + <dimen name="desktop_mode_handle_menu_app_info_pill_height">52dp</dimen> - <dimen name="freeform_resize_handle">30dp</dimen> + <!-- The height of the handle menu's "Windowing" pill in desktop mode. --> + <dimen name="desktop_mode_handle_menu_windowing_pill_height">52dp</dimen> - <dimen name="freeform_resize_corner">44dp</dimen> + <!-- The height of the handle menu's "More Actions" pill in desktop mode. --> + <dimen name="desktop_mode_handle_menu_more_actions_pill_height">156dp</dimen> - <!-- The radius of the caption menu shadow. --> - <dimen name="caption_menu_shadow_radius">4dp</dimen> + <!-- The top margin of the handle menu in desktop mode. --> + <dimen name="desktop_mode_handle_menu_margin_top">4dp</dimen> + + <!-- The start margin of the handle menu in desktop mode. --> + <dimen name="desktop_mode_handle_menu_margin_start">6dp</dimen> + + <!-- The margin between pills of the handle menu in desktop mode. --> + <dimen name="desktop_mode_handle_menu_pill_spacing_margin">2dp</dimen> <!-- The radius of the caption menu corners. --> - <dimen name="caption_menu_corner_radius">20dp</dimen> + <dimen name="desktop_mode_handle_menu_corner_radius">26dp</dimen> + <!-- The radius of the caption menu shadow. --> + <dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen> + + <dimen name="freeform_resize_handle">30dp</dimen> + + <dimen name="freeform_resize_corner">44dp</dimen> </resources> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index 395fdd1cfaa2..563fb4d88941 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -263,4 +263,6 @@ <string name="close_text">Close</string> <!-- Accessibility text for the handle menu close menu button [CHAR LIMIT=NONE] --> <string name="collapse_menu_text">Close Menu</string> + <!-- Accessibility text for the handle menu open menu button [CHAR LIMIT=NONE] --> + <string name="expand_menu_text">Open Menu</string> </resources> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index d0782ad9b37e..8cad385e1d3f 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -30,25 +30,31 @@ <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item> </style> - <style name="CaptionButtonStyle"> - <item name="android:layout_width">32dp</item> - <item name="android:layout_height">32dp</item> - <item name="android:layout_margin">5dp</item> - <item name="android:padding">4dp</item> + <style name="DesktopModeHandleMenuActionButton"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">52dp</item> + <item name="android:gravity">start|center_vertical</item> + <item name="android:padding">16dp</item> + <item name="android:textSize">14sp</item> + <item name="android:textFontWeight">500</item> + <item name="android:textColor">@color/desktop_mode_caption_menu_text_color</item> + <item name="android:drawablePadding">16dp</item> + <item name="android:background">?android:selectableItemBackground</item> </style> - <style name="CaptionWindowingButtonStyle"> - <item name="android:layout_width">40dp</item> - <item name="android:layout_height">40dp</item> - <item name="android:padding">4dp</item> + <style name="DesktopModeHandleMenuWindowingButton"> + <item name="android:layout_width">48dp</item> + <item name="android:layout_height">48dp</item> + <item name="android:padding">14dp</item> + <item name="android:scaleType">fitCenter</item> + <item name="android:background">?android:selectableItemBackgroundBorderless</item> </style> - <style name="CaptionMenuButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless"> - <item name="android:layout_width">match_parent</item> - <item name="android:layout_height">52dp</item> - <item name="android:layout_marginStart">10dp</item> + <style name="CaptionButtonStyle"> + <item name="android:layout_width">32dp</item> + <item name="android:layout_height">32dp</item> + <item name="android:layout_margin">5dp</item> <item name="android:padding">4dp</item> - <item name="android:gravity">start|center_vertical</item> </style> <style name="DockedDividerBackground"> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java index 8cbe44b15e42..e84a78f42616 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java @@ -52,4 +52,10 @@ public interface BackAnimation { * @param progressThreshold the max threshold to keep progressing back animation. */ void setSwipeThresholds(float triggerThreshold, float progressThreshold); + + /** + * Sets the system bar listener to control the system bar color. + * @param customizer the controller to control system bar color. + */ + void setStatusBarCustomizer(StatusBarCustomizer customizer); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java index 36cf29a4c4f3..9bf3b80d262e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java @@ -17,11 +17,17 @@ package com.android.wm.shell.back; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; + +import static com.android.wm.shell.back.BackAnimationConstants.UPDATE_SYSUI_FLAGS_THRESHOLD; import android.annotation.NonNull; import android.graphics.Color; +import android.graphics.Rect; import android.view.SurfaceControl; +import com.android.internal.graphics.ColorUtils; +import com.android.internal.view.AppearanceRegion; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; /** @@ -29,18 +35,35 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer; */ public class BackAnimationBackground { private static final int BACKGROUND_LAYER = -1; + + private static final int NO_APPEARANCE = 0; + private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private SurfaceControl mBackgroundSurface; + private StatusBarCustomizer mCustomizer; + private boolean mIsRequestingStatusBarAppearance; + private boolean mBackgroundIsDark; + private Rect mStartBounds; + public BackAnimationBackground(RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; } - void ensureBackground(int color, @NonNull SurfaceControl.Transaction transaction) { + /** + * Ensures the back animation background color layer is present. + * @param startRect The start bounds of the closing target. + * @param color The background color. + * @param transaction The animation transaction. + */ + void ensureBackground(Rect startRect, int color, + @NonNull SurfaceControl.Transaction transaction) { if (mBackgroundSurface != null) { return; } + mBackgroundIsDark = ColorUtils.calculateLuminance(color) < 0.5f; + final float[] colorComponents = new float[] { Color.red(color) / 255.f, Color.green(color) / 255.f, Color.blue(color) / 255.f }; @@ -54,6 +77,8 @@ public class BackAnimationBackground { transaction.setColor(mBackgroundSurface, colorComponents) .setLayer(mBackgroundSurface, BACKGROUND_LAYER) .show(mBackgroundSurface); + mStartBounds = startRect; + mIsRequestingStatusBarAppearance = false; } void removeBackground(@NonNull SurfaceControl.Transaction transaction) { @@ -65,5 +90,31 @@ public class BackAnimationBackground { transaction.remove(mBackgroundSurface); } mBackgroundSurface = null; + mIsRequestingStatusBarAppearance = false; + } + + void setStatusBarCustomizer(StatusBarCustomizer customizer) { + mCustomizer = customizer; + } + + void onBackProgressed(float progress) { + if (mCustomizer == null || mStartBounds.isEmpty()) { + return; + } + + final boolean shouldCustomizeSystemBar = progress > UPDATE_SYSUI_FLAGS_THRESHOLD; + if (shouldCustomizeSystemBar == mIsRequestingStatusBarAppearance) { + return; + } + + mIsRequestingStatusBarAppearance = shouldCustomizeSystemBar; + if (mIsRequestingStatusBarAppearance) { + final AppearanceRegion region = new AppearanceRegion(!mBackgroundIsDark + ? APPEARANCE_LIGHT_STATUS_BARS : NO_APPEARANCE, + mStartBounds); + mCustomizer.customizeStatusBarAppearance(region); + } else { + mCustomizer.customizeStatusBarAppearance(null); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationConstants.java new file mode 100644 index 000000000000..e06d3ef4e1ab --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationConstants.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.back; + +/** + * The common constant values used in back animators. + */ +class BackAnimationConstants { + static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.20f; + static final float PROGRESS_COMMIT_THRESHOLD = 0.1f; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 349ff36ce8ce..210c9aab14d6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -55,6 +55,7 @@ import android.window.IOnBackInvokedCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; +import com.android.internal.view.AppearanceRegion; import com.android.wm.shell.common.ExternalInterfaceBinder; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; @@ -142,6 +143,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont }); private final BackAnimationBackground mAnimationBackground; + private StatusBarCustomizer mCustomizer; public BackAnimationController( @NonNull ShellInit shellInit, @@ -268,6 +270,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mShellExecutor.execute(() -> BackAnimationController.this.setSwipeThresholds( triggerThreshold, progressThreshold)); } + + @Override + public void setStatusBarCustomizer(StatusBarCustomizer customizer) { + mCustomizer = customizer; + mAnimationBackground.setStatusBarCustomizer(customizer); + } } private static class IBackAnimationImpl extends IBackAnimation.Stub @@ -294,12 +302,23 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont BackNavigationInfo.TYPE_RETURN_TO_HOME)); } + public void customizeStatusBarAppearance(AppearanceRegion appearance) { + executeRemoteCallWithTaskPermission(mController, "useLauncherSysBarFlags", + (controller) -> controller.customizeStatusBarAppearance(appearance)); + } + @Override public void invalidate() { mController = null; } } + private void customizeStatusBarAppearance(AppearanceRegion appearance) { + if (mCustomizer != null) { + mCustomizer.customizeStatusBarAppearance(appearance); + } + } + void registerAnimation(@BackNavigationInfo.BackTargetType int type, @NonNull BackAnimationRunner runner) { mAnimationDefinition.set(type, runner); @@ -384,8 +403,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } private void onMove() { - if (!mBackGestureStarted || mBackNavigationInfo == null || !mEnableAnimations.get() - || mActiveCallback == null) { + if (!mBackGestureStarted || mBackNavigationInfo == null || mActiveCallback == null) { return; } @@ -424,9 +442,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } try { - if (mEnableAnimations.get()) { - callback.onBackStarted(backEvent); - } + callback.onBackStarted(backEvent); } catch (RemoteException e) { Log.e(TAG, "dispatchOnBackStarted error: ", e); } @@ -448,9 +464,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } try { - if (mEnableAnimations.get()) { - callback.onBackCancelled(); - } + callback.onBackCancelled(); } catch (RemoteException e) { Log.e(TAG, "dispatchOnBackCancelled error: ", e); } @@ -462,19 +476,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } try { - if (mEnableAnimations.get()) { - callback.onBackProgressed(backEvent); - } + callback.onBackProgressed(backEvent); } catch (RemoteException e) { Log.e(TAG, "dispatchOnBackProgressed error: ", e); } } - private boolean shouldDispatchAnimation(IOnBackInvokedCallback callback) { - // TODO(b/258698745): Only dispatch to animation callbacks. - return mEnableAnimations.get(); - } - /** * Sets to true when the back gesture has passed the triggering threshold, false otherwise. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java index da113cb579d6..22c90153bb39 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java @@ -19,6 +19,7 @@ package com.android.wm.shell.back; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; +import static com.android.wm.shell.back.BackAnimationConstants.PROGRESS_COMMIT_THRESHOLD; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import android.animation.Animator; @@ -89,7 +90,6 @@ class CrossActivityAnimation { private static final float WINDOW_X_SHIFT_DP = 96; private static final int SCALE_FACTOR = 100; // TODO(b/264710590): Use the progress commit threshold from ViewConfiguration once it exists. - private static final float PROGRESS_COMMIT_THRESHOLD = 0.1f; private static final float TARGET_COMMIT_PROGRESS = 0.5f; private static final float ENTER_ALPHA_THRESHOLD = 0.22f; @@ -184,7 +184,7 @@ class CrossActivityAnimation { mStartTaskRect.offsetTo(0, 0); // Draw background with task background color. - mBackground.ensureBackground( + mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(), mEnteringTarget.taskInfo.taskDescription.getBackgroundColor(), mTransaction); } @@ -244,6 +244,7 @@ class CrossActivityAnimation { : mapLinear(progress, 0, 1f, 0, TARGET_COMMIT_PROGRESS)) * SCALE_FACTOR; mLeavingProgressSpring.animateToFinalPosition(springProgress); mEnteringProgressSpring.animateToFinalPosition(springProgress); + mBackground.onBackProgressed(progress); } private void onGestureCommitted() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java index 99a434aff799..a7dd27a0784f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java @@ -141,7 +141,8 @@ class CrossTaskBackAnimation { mStartTaskRect.offsetTo(0, 0); // Draw background. - mBackground.ensureBackground(BACKGROUNDCOLOR, mTransaction); + mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(), + BACKGROUNDCOLOR, mTransaction); } private void updateGestureBackProgress(float progress, BackEvent event) { @@ -189,6 +190,8 @@ class CrossTaskBackAnimation { applyColorTransform(mClosingTarget.leash, closingColorScale); applyTransform(mEnteringTarget.leash, mEnteringCurrentRect, mCornerRadius); mTransaction.apply(); + + mBackground.onBackProgressed(progress); } private void updatePostCommitClosingAnimation(float progress) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java index ae33b9445acd..f0c5d8b29b2f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java @@ -25,7 +25,10 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Activity; import android.content.Context; +import android.graphics.Color; import android.graphics.Rect; import android.os.RemoteException; import android.util.FloatProperty; @@ -34,6 +37,7 @@ import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; +import android.view.WindowManager.LayoutParams; import android.view.animation.Animation; import android.view.animation.DecelerateInterpolator; import android.view.animation.Transformation; @@ -43,6 +47,7 @@ import android.window.BackNavigationInfo; import android.window.BackProgressAnimator; import android.window.IOnBackInvokedCallback; +import com.android.internal.R; import com.android.internal.dynamicanimation.animation.SpringAnimation; import com.android.internal.dynamicanimation.animation.SpringForce; import com.android.internal.policy.ScreenDecorationsUtils; @@ -78,6 +83,7 @@ class CustomizeActivityAnimation { final CustomAnimationLoader mCustomAnimationLoader; private Animation mEnterAnimation; private Animation mCloseAnimation; + private int mNextBackgroundColor; final Transformation mTransformation = new Transformation(); private final Choreographer mChoreographer; @@ -144,8 +150,11 @@ class CustomizeActivityAnimation { // Draw background with task background color. if (mEnteringTarget.taskInfo != null && mEnteringTarget.taskInfo.taskDescription != null) { - mBackground.ensureBackground( - mEnteringTarget.taskInfo.taskDescription.getBackgroundColor(), mTransaction); + mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(), + mNextBackgroundColor == Color.TRANSPARENT + ? mEnteringTarget.taskInfo.taskDescription.getBackgroundColor() + : mNextBackgroundColor, + mTransaction); } } @@ -191,6 +200,7 @@ class CustomizeActivityAnimation { mTransaction.apply(); mTransformation.clear(); mLatestProgress = 0; + mNextBackgroundColor = Color.TRANSPARENT; if (mFinishCallback != null) { try { mFinishCallback.onAnimationFinished(); @@ -252,11 +262,11 @@ class CustomizeActivityAnimation { * Load customize animation before animation start. */ boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo) { - mCloseAnimation = mCustomAnimationLoader.load( - animationInfo, false /* enterAnimation */); - if (mCloseAnimation != null) { - mEnterAnimation = mCustomAnimationLoader.load( - animationInfo, true /* enterAnimation */); + final AnimationLoadResult result = mCustomAnimationLoader.loadAll(animationInfo); + if (result != null) { + mCloseAnimation = result.mCloseAnimation; + mEnterAnimation = result.mEnterAnimation; + mNextBackgroundColor = result.mBackgroundColor; return true; } return false; @@ -318,35 +328,79 @@ class CustomizeActivityAnimation { } } + + static final class AnimationLoadResult { + Animation mCloseAnimation; + Animation mEnterAnimation; + int mBackgroundColor; + } + /** * Helper class to load custom animation. */ static class CustomAnimationLoader { - private final TransitionAnimation mTransitionAnimation; + final TransitionAnimation mTransitionAnimation; CustomAnimationLoader(Context context) { mTransitionAnimation = new TransitionAnimation( context, false /* debug */, "CustomizeBackAnimation"); } - Animation load(BackNavigationInfo.CustomAnimationInfo animationInfo, - boolean enterAnimation) { - final String packageName = animationInfo.getPackageName(); - if (packageName.isEmpty()) { + /** + * Load both enter and exit animation for the close activity transition. + * Note that the result is only valid if the exit animation has set and loaded success. + * If the entering animation has not set(i.e. 0), here will load the default entering + * animation for it. + * + * @param animationInfo The information of customize animation, which can be set from + * {@link Activity#overrideActivityTransition} and/or + * {@link LayoutParams#windowAnimations} + */ + AnimationLoadResult loadAll(BackNavigationInfo.CustomAnimationInfo animationInfo) { + if (animationInfo.getPackageName().isEmpty()) { return null; } - final int windowAnimations = animationInfo.getWindowAnimations(); - if (windowAnimations == 0) { + final Animation close = loadAnimation(animationInfo, false); + if (close == null) { return null; } - final int attrs = enterAnimation - ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation - : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; - Animation a = mTransitionAnimation.loadAnimationAttr(packageName, windowAnimations, - attrs, false /* translucent */); + final Animation open = loadAnimation(animationInfo, true); + AnimationLoadResult result = new AnimationLoadResult(); + result.mCloseAnimation = close; + result.mEnterAnimation = open; + result.mBackgroundColor = animationInfo.getCustomBackground(); + return result; + } + + /** + * Load enter or exit animation from CustomAnimationInfo + * @param animationInfo The information for customize animation. + * @param enterAnimation true when load for enter animation, false for exit animation. + * @return Loaded animation. + */ + @Nullable + Animation loadAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo, + boolean enterAnimation) { + Animation a = null; + // Activity#overrideActivityTransition has higher priority than windowAnimations + // Try to get animation from Activity#overrideActivityTransition + if ((enterAnimation && animationInfo.getCustomEnterAnim() != 0) + || (!enterAnimation && animationInfo.getCustomExitAnim() != 0)) { + a = mTransitionAnimation.loadAppTransitionAnimation( + animationInfo.getPackageName(), + enterAnimation ? animationInfo.getCustomEnterAnim() + : animationInfo.getCustomExitAnim()); + } else if (animationInfo.getWindowAnimations() != 0) { + // try to get animation from LayoutParams#windowAnimations + a = mTransitionAnimation.loadAnimationAttr(animationInfo.getPackageName(), + animationInfo.getWindowAnimations(), enterAnimation + ? R.styleable.WindowAnimation_activityCloseEnterAnimation + : R.styleable.WindowAnimation_activityCloseExitAnimation, + false /* translucent */); + } // Only allow to load default animation for opening target. if (a == null && enterAnimation) { - a = mTransitionAnimation.loadDefaultAnimationAttr(attrs, false /* translucent */); + a = loadDefaultOpenAnimation(); } if (a != null) { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "custom animation loaded %s", a); @@ -355,5 +409,11 @@ class CustomizeActivityAnimation { } return a; } + + private Animation loadDefaultOpenAnimation() { + return mTransitionAnimation.loadDefaultAnimationAttr( + R.styleable.WindowAnimation_activityCloseEnterAnimation, + false /* translucent */); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl index 2b2a0e397792..1a35de47e977 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl @@ -16,8 +16,9 @@ package com.android.wm.shell.back; -import android.window.IOnBackInvokedCallback; +import com.android.internal.view.AppearanceRegion; import android.view.IRemoteAnimationRunner; +import android.window.IOnBackInvokedCallback; /** * Interface for Launcher process to register back invocation callbacks. @@ -34,4 +35,9 @@ interface IBackAnimation { * Clears the previously registered {@link IOnBackInvokedCallback}. */ void clearBackToLauncherCallback(); + + /** + * Uses launcher flags to update the system bar color. + */ + void customizeStatusBarAppearance(in AppearanceRegion appearance); } diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeHeightLog.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/StatusBarCustomizer.java index 6fe868655ee6..5e876127e9b4 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeHeightLog.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/StatusBarCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.systemui.log.dagger; +package com.android.wm.shell.back; -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.android.internal.view.AppearanceRegion; -import com.android.systemui.plugins.log.LogBuffer; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Qualifier; - -/** A {@link LogBuffer} for Shade height changes. */ -@Qualifier -@Documented -@Retention(RUNTIME) -public @interface ShadeHeightLog { +/** + * Interface to customize the system bar color. + */ +public interface StatusBarCustomizer { + /** + * Called when the status bar color needs to be changed. + * @param appearance The region of appearance. + */ + void customizeStatusBarAppearance(AppearanceRegion appearance); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index 85a353f2d586..5f2b63089009 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -47,6 +47,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; +import com.android.wm.shell.common.bubbles.BubbleInfo; import java.io.PrintWriter; import java.util.List; @@ -244,6 +245,16 @@ public class Bubble implements BubbleViewProvider { setEntry(entry); } + /** Converts this bubble into a {@link BubbleInfo} object to be shared with external callers. */ + public BubbleInfo asBubbleBarBubble() { + return new BubbleInfo(getKey(), + getFlags(), + getShortcutInfo().getId(), + getIcon(), + getUser().getIdentifier(), + getPackageName()); + } + @Override public String getKey() { return mKey; @@ -545,8 +556,13 @@ public class Bubble implements BubbleViewProvider { } } + /** + * @return the icon set on BubbleMetadata, if it exists. This is only non-null for bubbles + * created via a PendingIntent. This is null for bubbles created by a shortcut, as we use the + * icon from the shortcut. + */ @Nullable - Icon getIcon() { + public Icon getIcon() { return mIcon; } @@ -640,6 +656,13 @@ public class Bubble implements BubbleViewProvider { } /** + * Whether this bubble is conversation + */ + public boolean isConversation() { + return null != mShortcutInfo; + } + + /** * Sets whether this notification should be suppressed in the shade. */ @VisibleForTesting diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index d2889e782aea..3dbb745f0c6c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -38,7 +38,9 @@ import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NO_LONGER_BUBBLE; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_PACKAGE_REMOVED; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_SHORTCUT_REMOVED; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES; +import android.annotation.BinderThread; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.ActivityManager; @@ -59,6 +61,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Icon; import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; @@ -85,16 +88,19 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ExternalInterfaceBinder; import com.android.wm.shell.common.FloatingContentCoordinator; +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.SingleInstanceRemoteListener; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.annotations.ShellBackgroundThread; import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.common.bubbles.BubbleBarUpdate; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.onehanded.OneHandedTransitionCallback; @@ -103,6 +109,8 @@ import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.taskview.TaskView; +import com.android.wm.shell.taskview.TaskViewTransitions; import java.io.PrintWriter; import java.util.ArrayList; @@ -123,7 +131,8 @@ import java.util.function.IntConsumer; * * The controller manages addition, removal, and visible state of bubbles on screen. */ -public class BubbleController implements ConfigurationChangeListener { +public class BubbleController implements ConfigurationChangeListener, + RemoteCallable<BubbleController> { private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES; @@ -248,6 +257,8 @@ public class BubbleController implements ConfigurationChangeListener { private Optional<OneHandedController> mOneHandedOptional; /** Drag and drop controller to register listener for onDragStarted. */ private DragAndDropController mDragAndDropController; + /** Used to send bubble events to launcher. */ + private Bubbles.BubbleStateListener mBubbleStateListener; public BubbleController(Context context, ShellInit shellInit, @@ -458,9 +469,15 @@ public class BubbleController implements ConfigurationChangeListener { mCurrentProfiles = userProfiles; mShellController.addConfigurationChangeListener(this); + mShellController.addExternalInterface(KEY_EXTRA_SHELL_BUBBLES, + this::createExternalInterface, this); mShellCommandHandler.addDumpCallback(this::dump, this); } + private ExternalInterfaceBinder createExternalInterface() { + return new BubbleController.IBubblesImpl(this); + } + @VisibleForTesting public Bubbles asBubbles() { return mImpl; @@ -475,6 +492,48 @@ public class BubbleController implements ConfigurationChangeListener { return mMainExecutor; } + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; + } + + /** + * Sets a listener to be notified of bubble updates. This is used by launcher so that + * it may render bubbles in itself. Only one listener is supported. + */ + public void registerBubbleStateListener(Bubbles.BubbleStateListener listener) { + if (isShowingAsBubbleBar()) { + // Only set the listener if bubble bar is showing. + mBubbleStateListener = listener; + sendInitialListenerUpdate(); + } else { + mBubbleStateListener = null; + } + } + + /** + * Unregisters the {@link Bubbles.BubbleStateListener}. + */ + public void unregisterBubbleStateListener() { + mBubbleStateListener = null; + } + + /** + * If a {@link Bubbles.BubbleStateListener} is present, this will send the current bubble + * state to it. + */ + private void sendInitialListenerUpdate() { + if (mBubbleStateListener != null) { + BubbleBarUpdate update = mBubbleData.getInitialStateForBubbleBar(); + mBubbleStateListener.onBubbleStateChange(update); + } + } + /** * Hides the current input method, wherever it may be focused, via InputMethodManagerInternal. */ @@ -1648,7 +1707,7 @@ public class BubbleController implements ConfigurationChangeListener { /** * Whether an intent is properly configured to display in a - * {@link com.android.wm.shell.TaskView}. + * {@link TaskView}. * * Keep checks in sync with BubbleExtractor#canLaunchInTaskView. Typically * that should filter out any invalid bubbles, but should protect SysUI side just in case. @@ -1722,6 +1781,73 @@ public class BubbleController implements ConfigurationChangeListener { } } + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private class IBubblesImpl extends IBubbles.Stub implements ExternalInterfaceBinder { + private BubbleController mController; + private final SingleInstanceRemoteListener<BubbleController, IBubblesListener> mListener; + private final Bubbles.BubbleStateListener mBubbleListener = + new Bubbles.BubbleStateListener() { + + @Override + public void onBubbleStateChange(BubbleBarUpdate update) { + Bundle b = new Bundle(); + b.setClassLoader(BubbleBarUpdate.class.getClassLoader()); + b.putParcelable(BubbleBarUpdate.BUNDLE_KEY, update); + mListener.call(l -> l.onBubbleStateChange(b)); + } + }; + + IBubblesImpl(BubbleController controller) { + mController = controller; + mListener = new SingleInstanceRemoteListener<>(mController, + c -> c.registerBubbleStateListener(mBubbleListener), + c -> c.unregisterBubbleStateListener()); + } + + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + @Override + public void invalidate() { + mController = null; + } + + @Override + public void registerBubbleListener(IBubblesListener listener) { + mMainExecutor.execute(() -> { + mListener.register(listener); + }); + } + + @Override + public void unregisterBubbleListener(IBubblesListener listener) { + mMainExecutor.execute(() -> mListener.unregister()); + } + + @Override + public void showBubble(String key, boolean onLauncherHome) { + // TODO + } + + @Override + public void removeBubble(String key, int reason) { + // TODO + } + + @Override + public void collapseBubbles() { + // TODO + } + + @Override + public void onTaskbarStateChanged(int newState) { + // TODO (b/269670598) + } + } + private class BubblesImpl implements Bubbles { // Up-to-date cached state of bubbles data for SysUI to query from the calling thread @VisibleForTesting @@ -1835,6 +1961,17 @@ public class BubbleController implements ConfigurationChangeListener { private CachedState mCachedState = new CachedState(); + private IBubblesImpl mIBubbles; + + @Override + public IBubbles createExternalInterface() { + if (mIBubbles != null) { + mIBubbles.invalidate(); + } + mIBubbles = new IBubblesImpl(BubbleController.this); + return mIBubbles; + } + @Override public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) { return mCachedState.isBubbleNotificationSuppressedFromShade(key, groupKey); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 3fd09675a245..a26c0c487d19 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -40,6 +40,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.wm.shell.R; import com.android.wm.shell.bubbles.Bubbles.DismissReason; +import com.android.wm.shell.common.bubbles.BubbleBarUpdate; +import com.android.wm.shell.common.bubbles.RemovedBubble; import java.io.PrintWriter; import java.util.ArrayList; @@ -113,6 +115,61 @@ public class BubbleData { void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) { removedBubbles.add(new Pair<>(bubbleToRemove, reason)); } + + /** + * Converts the update to a {@link BubbleBarUpdate} which contains updates relevant + * to the bubble bar. Only used when {@link BubbleController#isShowingAsBubbleBar()} is + * true. + */ + BubbleBarUpdate toBubbleBarUpdate() { + BubbleBarUpdate bubbleBarUpdate = new BubbleBarUpdate(); + + bubbleBarUpdate.expandedChanged = expandedChanged; + bubbleBarUpdate.expanded = expanded; + if (selectionChanged) { + bubbleBarUpdate.selectedBubbleKey = selectedBubble != null + ? selectedBubble.getKey() + : null; + } + bubbleBarUpdate.addedBubble = addedBubble != null + ? addedBubble.asBubbleBarBubble() + : null; + // TODO(b/269670235): We need to handle updates better, I think for the bubble bar only + // certain updates need to be sent instead of any updatedBubble. + bubbleBarUpdate.updatedBubble = updatedBubble != null + ? updatedBubble.asBubbleBarBubble() + : null; + bubbleBarUpdate.suppressedBubbleKey = suppressedBubble != null + ? suppressedBubble.getKey() + : null; + bubbleBarUpdate.unsupressedBubbleKey = unsuppressedBubble != null + ? unsuppressedBubble.getKey() + : null; + for (int i = 0; i < removedBubbles.size(); i++) { + Pair<Bubble, Integer> pair = removedBubbles.get(i); + bubbleBarUpdate.removedBubbles.add( + new RemovedBubble(pair.first.getKey(), pair.second)); + } + if (orderChanged) { + // Include the new order + for (int i = 0; i < bubbles.size(); i++) { + bubbleBarUpdate.bubbleKeysInOrder.add(bubbles.get(i).getKey()); + } + } + return bubbleBarUpdate; + } + + /** + * Gets the current state of active bubbles and populates the update with that. Only + * used when {@link BubbleController#isShowingAsBubbleBar()} is true. + */ + BubbleBarUpdate getInitialState() { + BubbleBarUpdate bubbleBarUpdate = new BubbleBarUpdate(); + for (int i = 0; i < bubbles.size(); i++) { + bubbleBarUpdate.currentBubbleList.add(bubbles.get(i).asBubbleBarBubble()); + } + return bubbleBarUpdate; + } } /** @@ -190,6 +247,13 @@ public class BubbleData { mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow); } + /** + * Returns a bubble bar update populated with the current list of active bubbles. + */ + public BubbleBarUpdate getInitialStateForBubbleBar() { + return mStateChange.getInitialState(); + } + public void setSuppressionChangedListener(Bubbles.BubbleMetadataFlagListener listener) { mBubbleMetadataFlagListener = listener; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 9ccd6ebc51e2..a317c449621b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -67,10 +67,10 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.wm.shell.R; -import com.android.wm.shell.TaskView; -import com.android.wm.shell.TaskViewTaskController; import com.android.wm.shell.common.AlphaOptimizedButton; import com.android.wm.shell.common.TriangleShape; +import com.android.wm.shell.taskview.TaskView; +import com.android.wm.shell.taskview.TaskViewTaskController; import java.io.PrintWriter; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 5ea2450114f0..d101b0c4d7e8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -53,12 +53,16 @@ public class BubblePositioner { public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f; /** The max percent of screen width to use for the flyout on phone. */ public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f; - /** The percent of screen width that should be used for the expanded view on a large screen. **/ + /** The percent of screen width for the expanded view on a large screen. **/ private static final float EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT = 0.48f; - /** The percent of screen width that should be used for the expanded view on a large screen. **/ + /** The percent of screen width for the expanded view on a large screen. **/ private static final float EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT = 0.70f; - /** The percent of screen width that should be used for the expanded view on a small tablet. **/ + /** The percent of screen width for the expanded view on a small tablet. **/ private static final float EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT = 0.72f; + /** The percent of screen width for the expanded view when shown in the bubble bar. **/ + private static final float EXPANDED_VIEW_BUBBLE_BAR_PORTRAIT_WIDTH_PERCENT = 0.7f; + /** The percent of screen width for the expanded view when shown in the bubble bar. **/ + private static final float EXPANDED_VIEW_BUBBLE_BAR_LANDSCAPE_WIDTH_PERCENT = 0.4f; private Context mContext; private WindowManager mWindowManager; @@ -97,6 +101,12 @@ public class BubblePositioner { private PointF mRestingStackPosition; private int[] mPaddings = new int[4]; + private boolean mShowingInBubbleBar; + private boolean mBubblesOnHome; + private int mBubbleBarSize; + private int mBubbleBarHomeAdjustment; + private final PointF mBubbleBarPosition = new PointF(); + public BubblePositioner(Context context, WindowManager windowManager) { mContext = context; mWindowManager = windowManager; @@ -133,6 +143,7 @@ public class BubblePositioner { + " insets: " + insets + " isLargeScreen: " + mIsLargeScreen + " isSmallTablet: " + mIsSmallTablet + + " showingInBubbleBar: " + mShowingInBubbleBar + " bounds: " + bounds); } updateInternal(mRotation, insets, bounds); @@ -155,11 +166,17 @@ public class BubblePositioner { mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing); mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered); mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding); + mBubbleBarHomeAdjustment = mExpandedViewPadding / 2; mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); mBubbleOffscreenAmount = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen); mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset); + mBubbleBarSize = res.getDimensionPixelSize(R.dimen.bubblebar_size); - if (mIsSmallTablet) { + if (mShowingInBubbleBar) { + mExpandedViewLargeScreenWidth = isLandscape() + ? (int) (bounds.width() * EXPANDED_VIEW_BUBBLE_BAR_LANDSCAPE_WIDTH_PERCENT) + : (int) (bounds.width() * EXPANDED_VIEW_BUBBLE_BAR_PORTRAIT_WIDTH_PERCENT); + } else if (mIsSmallTablet) { mExpandedViewLargeScreenWidth = (int) (bounds.width() * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT); } else { @@ -693,4 +710,65 @@ public class BubblePositioner { screen.right, screen.bottom); } + + // + // Bubble bar specific sizes below. + // + + /** + * Sets whether bubbles are showing in the bubble bar from launcher. + */ + public void setShowingInBubbleBar(boolean showingInBubbleBar) { + mShowingInBubbleBar = showingInBubbleBar; + } + + /** + * Sets whether bubbles are showing on launcher home, in which case positions are different. + */ + public void setBubblesOnHome(boolean bubblesOnHome) { + mBubblesOnHome = bubblesOnHome; + } + + /** + * How wide the expanded view should be when showing from the bubble bar. + */ + public int getExpandedViewWidthForBubbleBar() { + return mExpandedViewLargeScreenWidth; + } + + /** + * How tall the expanded view should be when showing from the bubble bar. + */ + public int getExpandedViewHeightForBubbleBar() { + return getAvailableRect().height() + - mBubbleBarSize + - mExpandedViewPadding * 2 + - getBubbleBarHomeAdjustment(); + } + + /** + * The amount of padding from the edge of the screen to the expanded view when in bubble bar. + */ + public int getBubbleBarExpandedViewPadding() { + return mExpandedViewPadding; + } + + /** + * Returns the on screen co-ordinates of the bubble bar. + */ + public PointF getBubbleBarPosition() { + mBubbleBarPosition.set(getAvailableRect().width() - mBubbleBarSize, + getAvailableRect().height() - mBubbleBarSize + - mExpandedViewPadding - getBubbleBarHomeAdjustment()); + return mBubbleBarPosition; + } + + /** + * When bubbles are shown on launcher home, there's an extra bit of padding that needs to + * be applied between the expanded view and the bubble bar. This returns the adjustment value + * if bubbles are showing on home. + */ + private int getBubbleBarHomeAdjustment() { + return mBubblesOnHome ? mBubbleBarHomeAdjustment : 0; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index deb4fd5f19bb..66241628fc77 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -33,7 +33,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; -import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -575,7 +574,7 @@ public class BubbleStackView extends FrameLayout if (maybeShowStackEdu()) { mShowedUserEducationInTouchListenerActive = true; return true; - } else if (isStackEduShowing()) { + } else if (isStackEduVisible()) { mStackEduView.hide(false /* fromExpansion */); } @@ -651,7 +650,7 @@ public class BubbleStackView extends FrameLayout mExpandedAnimationController.dragBubbleOut( v, viewInitialX + dx, viewInitialY + dy); } else { - if (isStackEduShowing()) { + if (isStackEduVisible()) { mStackEduView.hide(false /* fromExpansion */); } mStackAnimationController.moveStackFromTouch( @@ -733,8 +732,7 @@ public class BubbleStackView extends FrameLayout @Override public void onMove(float dx, float dy) { - if ((mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) - || isStackEduShowing()) { + if (isManageEduVisible() || isStackEduVisible()) { return; } @@ -996,7 +994,7 @@ public class BubbleStackView extends FrameLayout mStackAnimationController.updateResources(); mBubbleOverflow.updateResources(); - if (!isStackEduShowing() && mRelativeStackPositionBeforeRotation != null) { + if (!isStackEduVisible() && mRelativeStackPositionBeforeRotation != null) { mStackAnimationController.setStackPosition( mRelativeStackPositionBeforeRotation); mRelativeStackPositionBeforeRotation = null; @@ -1046,9 +1044,9 @@ public class BubbleStackView extends FrameLayout setOnClickListener(view -> { if (mShowingManage) { showManageMenu(false /* show */); - } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) { + } else if (isManageEduVisible()) { mManageEduView.hide(); - } else if (isStackEduShowing()) { + } else if (isStackEduVisible()) { mStackEduView.hide(false /* isExpanding */); } else if (mBubbleData.isExpanded()) { mBubbleData.setExpanded(false); @@ -1247,10 +1245,19 @@ public class BubbleStackView extends FrameLayout } /** + * Whether the selected bubble is conversation bubble + */ + private boolean isConversationBubble() { + BubbleViewProvider bubble = mBubbleData.getSelectedBubble(); + return bubble instanceof Bubble && ((Bubble) bubble).isConversation(); + } + + /** * Whether the educational view should show for the expanded view "manage" menu. */ private boolean shouldShowManageEdu() { - if (ActivityManager.isRunningInTestHarness()) { + if (!isConversationBubble()) { + // We only show user education for conversation bubbles right now return false; } final boolean seen = getPrefBoolean(ManageEducationViewKt.PREF_MANAGED_EDUCATION); @@ -1273,11 +1280,17 @@ public class BubbleStackView extends FrameLayout mManageEduView.show(mExpandedBubble.getExpandedView()); } + @VisibleForTesting + public boolean isManageEduVisible() { + return mManageEduView != null && mManageEduView.getVisibility() == VISIBLE; + } + /** * Whether education view should show for the collapsed stack. */ private boolean shouldShowStackEdu() { - if (ActivityManager.isRunningInTestHarness()) { + if (!isConversationBubble()) { + // We only show user education for conversation bubbles right now return false; } final boolean seen = getPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION); @@ -1310,13 +1323,14 @@ public class BubbleStackView extends FrameLayout return mStackEduView.show(mPositioner.getDefaultStartPosition()); } - private boolean isStackEduShowing() { + @VisibleForTesting + public boolean isStackEduVisible() { return mStackEduView != null && mStackEduView.getVisibility() == VISIBLE; } // Recreates & shows the education views. Call when a theme/config change happens. private void updateUserEdu() { - if (isStackEduShowing()) { + if (isStackEduVisible()) { removeView(mStackEduView); mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController); addView(mStackEduView); @@ -1325,7 +1339,7 @@ public class BubbleStackView extends FrameLayout mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition()); mStackEduView.show(mPositioner.getDefaultStartPosition()); } - if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) { + if (isManageEduVisible()) { removeView(mManageEduView); mManageEduView = new ManageEducationView(mContext, mPositioner); addView(mManageEduView); @@ -1429,7 +1443,7 @@ public class BubbleStackView extends FrameLayout mStackAnimationController.updateResources(); mDismissView.updateResources(); mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2); - if (!isStackEduShowing()) { + if (!isStackEduVisible()) { mStackAnimationController.setStackPosition( new RelativeStackPosition( mPositioner.getRestingPosition(), @@ -2013,7 +2027,7 @@ public class BubbleStackView extends FrameLayout if (mIsExpanded) { if (mShowingManage) { showManageMenu(false); - } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) { + } else if (isManageEduVisible()) { mManageEduView.hide(); } else { mBubbleData.setExpanded(false); @@ -2158,7 +2172,7 @@ public class BubbleStackView extends FrameLayout cancelDelayedExpandCollapseSwitchAnimations(); final boolean showVertically = mPositioner.showBubblesVertically(); mIsExpanded = true; - if (isStackEduShowing()) { + if (isStackEduVisible()) { mStackEduView.hide(true /* fromExpansion */); } beforeExpandedViewAnimation(); @@ -2280,7 +2294,7 @@ public class BubbleStackView extends FrameLayout private void animateCollapse() { cancelDelayedExpandCollapseSwitchAnimations(); - if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) { + if (isManageEduVisible()) { mManageEduView.hide(); } @@ -2677,7 +2691,7 @@ public class BubbleStackView extends FrameLayout if (flyoutMessage == null || flyoutMessage.message == null || !bubble.showFlyout() - || isStackEduShowing() + || isStackEduVisible() || isExpanded() || mIsExpansionAnimating || mIsGestureInProgress @@ -2800,7 +2814,7 @@ public class BubbleStackView extends FrameLayout * them. */ public void getTouchableRegion(Rect outRect) { - if (isStackEduShowing()) { + if (isStackEduVisible()) { // When user education shows then capture all touches outRect.set(0, 0, getWidth(), getHeight()); return; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java new file mode 100644 index 000000000000..7a5815994dd0 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.bubbles; + +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; + +import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW; + +import android.app.ActivityOptions; +import android.app.ActivityTaskManager; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.os.RemoteException; +import android.util.Log; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.taskview.TaskView; +import com.android.wm.shell.taskview.TaskViewTaskController; + +/** + * Handles creating and updating the {@link TaskView} associated with a {@link Bubble}. + */ +public class BubbleTaskViewHelper { + + private static final String TAG = BubbleTaskViewHelper.class.getSimpleName(); + + /** + * Listener for users of {@link BubbleTaskViewHelper} to use to be notified of events + * on the task. + */ + public interface Listener { + + /** Called when the task is first created. */ + void onTaskCreated(); + + /** Called when the visibility of the task changes. */ + void onContentVisibilityChanged(boolean visible); + + /** Called when back is pressed on the task root. */ + void onBackPressed(); + } + + private final Context mContext; + private final BubbleController mController; + private final @ShellMainThread ShellExecutor mMainExecutor; + private final BubbleTaskViewHelper.Listener mListener; + private final View mParentView; + + @Nullable + private Bubble mBubble; + @Nullable + private PendingIntent mPendingIntent; + private TaskViewTaskController mTaskViewTaskController; + @Nullable + private TaskView mTaskView; + private int mTaskId = INVALID_TASK_ID; + + private final TaskView.Listener mTaskViewListener = new TaskView.Listener() { + private boolean mInitialized = false; + private boolean mDestroyed = false; + + @Override + public void onInitialized() { + if (DEBUG_BUBBLE_EXPANDED_VIEW) { + Log.d(TAG, "onInitialized: destroyed=" + mDestroyed + + " initialized=" + mInitialized + + " bubble=" + getBubbleKey()); + } + + if (mDestroyed || mInitialized) { + return; + } + + // Custom options so there is no activity transition animation + ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, + 0 /* enterResId */, 0 /* exitResId */); + + Rect launchBounds = new Rect(); + mTaskView.getBoundsOnScreen(launchBounds); + + // TODO: I notice inconsistencies in lifecycle + // Post to keep the lifecycle normal + mParentView.post(() -> { + if (DEBUG_BUBBLE_EXPANDED_VIEW) { + Log.d(TAG, "onInitialized: calling startActivity, bubble=" + + getBubbleKey()); + } + try { + options.setTaskAlwaysOnTop(true); + options.setLaunchedFromBubble(true); + + Intent fillInIntent = new Intent(); + // Apply flags to make behaviour match documentLaunchMode=always. + fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); + fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + + if (mBubble.isAppBubble()) { + PendingIntent pi = PendingIntent.getActivity(mContext, 0, + mBubble.getAppBubbleIntent(), + PendingIntent.FLAG_MUTABLE, + null); + mTaskView.startActivity(pi, fillInIntent, options, launchBounds); + } else if (mBubble.hasMetadataShortcutId()) { + options.setApplyActivityFlagsForBubbles(true); + mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), + options, launchBounds); + } else { + if (mBubble != null) { + mBubble.setIntentActive(); + } + mTaskView.startActivity(mPendingIntent, fillInIntent, options, + launchBounds); + } + } catch (RuntimeException e) { + // If there's a runtime exception here then there's something + // wrong with the intent, we can't really recover / try to populate + // the bubble again so we'll just remove it. + Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey() + + ", " + e.getMessage() + "; removing bubble"); + mController.removeBubble(getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT); + } + mInitialized = true; + }); + } + + @Override + public void onReleased() { + mDestroyed = true; + } + + @Override + public void onTaskCreated(int taskId, ComponentName name) { + if (DEBUG_BUBBLE_EXPANDED_VIEW) { + Log.d(TAG, "onTaskCreated: taskId=" + taskId + + " bubble=" + getBubbleKey()); + } + // The taskId is saved to use for removeTask, preventing appearance in recent tasks. + mTaskId = taskId; + + // With the task org, the taskAppeared callback will only happen once the task has + // already drawn + mListener.onTaskCreated(); + } + + @Override + public void onTaskVisibilityChanged(int taskId, boolean visible) { + mListener.onContentVisibilityChanged(visible); + } + + @Override + public void onTaskRemovalStarted(int taskId) { + if (DEBUG_BUBBLE_EXPANDED_VIEW) { + Log.d(TAG, "onTaskRemovalStarted: taskId=" + taskId + + " bubble=" + getBubbleKey()); + } + if (mBubble != null) { + mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED); + } + } + + @Override + public void onBackPressedOnTaskRoot(int taskId) { + if (mTaskId == taskId && mController.isStackExpanded()) { + mListener.onBackPressed(); + } + } + }; + + public BubbleTaskViewHelper(Context context, + BubbleController controller, + BubbleTaskViewHelper.Listener listener, + View parent) { + mContext = context; + mController = controller; + mMainExecutor = mController.getMainExecutor(); + mListener = listener; + mParentView = parent; + mTaskViewTaskController = new TaskViewTaskController(mContext, + mController.getTaskOrganizer(), + mController.getTaskViewTransitions(), mController.getSyncTransactionQueue()); + mTaskView = new TaskView(mContext, mTaskViewTaskController); + mTaskView.setListener(mMainExecutor, mTaskViewListener); + } + + /** + * Sets the bubble or updates the bubble used to populate the view. + * + * @return true if the bubble is new, false if it was an update to the same bubble. + */ + public boolean update(Bubble bubble) { + boolean isNew = mBubble == null || didBackingContentChange(bubble); + mBubble = bubble; + if (isNew) { + mPendingIntent = mBubble.getBubbleIntent(); + return true; + } + return false; + } + + /** Cleans up anything related to the task and {@code TaskView}. */ + public void cleanUpTaskView() { + if (DEBUG_BUBBLE_EXPANDED_VIEW) { + Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId); + } + if (mTaskId != INVALID_TASK_ID) { + try { + ActivityTaskManager.getService().removeTask(mTaskId); + } catch (RemoteException e) { + Log.w(TAG, e.getMessage()); + } + } + if (mTaskView != null) { + mTaskView.release(); + mTaskView = null; + } + } + + /** Returns the bubble key associated with this view. */ + @Nullable + public String getBubbleKey() { + return mBubble != null ? mBubble.getKey() : null; + } + + /** Returns the TaskView associated with this view. */ + @Nullable + public TaskView getTaskView() { + return mTaskView; + } + + /** + * Returns the task id associated with the task in this view. If the task doesn't exist then + * {@link ActivityTaskManager#INVALID_TASK_ID}. + */ + public int getTaskId() { + return mTaskId; + } + + /** Returns whether the bubble set on the helper is valid to populate the task view. */ + public boolean isValidBubble() { + return mBubble != null && (mPendingIntent != null || mBubble.hasMetadataShortcutId()); + } + + // TODO (b/274980695): Is this still relevant? + /** + * Bubbles are backed by a pending intent or a shortcut, once the activity is + * started we never change it / restart it on notification updates -- unless the bubble's + * backing data switches. + * + * This indicates if the new bubble is backed by a different data source than what was + * previously shown here (e.g. previously a pending intent & now a shortcut). + * + * @param newBubble the bubble this view is being updated with. + * @return true if the backing content has changed. + */ + private boolean didBackingContentChange(Bubble newBubble) { + boolean prevWasIntentBased = mBubble != null && mPendingIntent != null; + boolean newIsIntentBased = newBubble.getBubbleIntent() != null; + return prevWasIntentBased != newIsIntentBased; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java index 876a720f7722..259f69296ac7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java @@ -39,6 +39,7 @@ import androidx.annotation.IntDef; import androidx.annotation.Nullable; import com.android.wm.shell.common.annotations.ExternalThread; +import com.android.wm.shell.common.bubbles.BubbleBarUpdate; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -81,6 +82,11 @@ public interface Bubbles { int DISMISS_RELOAD_FROM_DISK = 15; int DISMISS_USER_REMOVED = 16; + /** Returns a binder that can be passed to an external process to manipulate Bubbles. */ + default IBubbles createExternalInterface() { + return null; + } + /** * @return {@code true} if there is a bubble associated with the provided key and if its * notification is hidden from the shade or there is a group summary associated with the @@ -277,6 +283,17 @@ public interface Bubbles { */ void onUserRemoved(int removedUserId); + /** + * A listener to be notified of bubble state changes, used by launcher to render bubbles in + * its process. + */ + interface BubbleStateListener { + /** + * Called when the bubbles state changes. + */ + void onBubbleStateChange(BubbleBarUpdate update); + } + /** Listener to find out about stack expansion / collapse events. */ interface BubbleExpandListener { /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl new file mode 100644 index 000000000000..862e818a998b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.bubbles; + +import android.content.Intent; +import com.android.wm.shell.bubbles.IBubblesListener; + +/** + * Interface that is exposed to remote callers (launcher) to manipulate the bubbles feature when + * showing in the bubble bar. + */ +interface IBubbles { + + oneway void registerBubbleListener(in IBubblesListener listener) = 1; + + oneway void unregisterBubbleListener(in IBubblesListener listener) = 2; + + oneway void showBubble(in String key, in boolean onLauncherHome) = 3; + + oneway void removeBubble(in String key, in int reason) = 4; + + oneway void collapseBubbles() = 5; + + oneway void onTaskbarStateChanged(in int newState) = 6; + +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubblesListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubblesListener.aidl new file mode 100644 index 000000000000..e48f8d5f1c84 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubblesListener.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.bubbles; +import android.os.Bundle; + +/** + * Listener interface that Launcher attaches to SystemUI to get bubbles callbacks. + */ +oneway interface IBubblesListener { + + /** + * Called when the bubbles state changes. + */ + void onBubbleStateChange(in Bundle update); +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleBarUpdate.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleBarUpdate.java new file mode 100644 index 000000000000..81423473171d --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleBarUpdate.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common.bubbles; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents an update to bubbles state. This is passed through + * {@link com.android.wm.shell.bubbles.IBubblesListener} to launcher so that taskbar may render + * bubbles. This should be kept this as minimal as possible in terms of data. + */ +public class BubbleBarUpdate implements Parcelable { + + public static final String BUNDLE_KEY = "update"; + + public boolean expandedChanged; + public boolean expanded; + @Nullable + public String selectedBubbleKey; + @Nullable + public BubbleInfo addedBubble; + @Nullable + public BubbleInfo updatedBubble; + @Nullable + public String suppressedBubbleKey; + @Nullable + public String unsupressedBubbleKey; + + // This is only populated if bubbles have been removed. + public List<RemovedBubble> removedBubbles = new ArrayList<>(); + + // This is only populated if the order of the bubbles has changed. + public List<String> bubbleKeysInOrder = new ArrayList<>(); + + // This is only populated the first time a listener is connected so it gets the current state. + public List<BubbleInfo> currentBubbleList = new ArrayList<>(); + + public BubbleBarUpdate() { + } + + public BubbleBarUpdate(Parcel parcel) { + expandedChanged = parcel.readBoolean(); + expanded = parcel.readBoolean(); + selectedBubbleKey = parcel.readString(); + addedBubble = parcel.readParcelable(BubbleInfo.class.getClassLoader(), + BubbleInfo.class); + updatedBubble = parcel.readParcelable(BubbleInfo.class.getClassLoader(), + BubbleInfo.class); + suppressedBubbleKey = parcel.readString(); + unsupressedBubbleKey = parcel.readString(); + removedBubbles = parcel.readParcelableList(new ArrayList<>(), + RemovedBubble.class.getClassLoader()); + parcel.readStringList(bubbleKeysInOrder); + currentBubbleList = parcel.readParcelableList(new ArrayList<>(), + BubbleInfo.class.getClassLoader()); + } + + /** + * Returns whether anything has changed in this update. + */ + public boolean anythingChanged() { + return expandedChanged + || selectedBubbleKey != null + || addedBubble != null + || updatedBubble != null + || !removedBubbles.isEmpty() + || !bubbleKeysInOrder.isEmpty() + || suppressedBubbleKey != null + || unsupressedBubbleKey != null + || !currentBubbleList.isEmpty(); + } + + @Override + public String toString() { + return "BubbleBarUpdate{ expandedChanged=" + expandedChanged + + " expanded=" + expanded + + " selectedBubbleKey=" + selectedBubbleKey + + " addedBubble=" + addedBubble + + " updatedBubble=" + updatedBubble + + " suppressedBubbleKey=" + suppressedBubbleKey + + " unsuppressedBubbleKey=" + unsupressedBubbleKey + + " removedBubbles=" + removedBubbles + + " bubbles=" + bubbleKeysInOrder + + " currentBubbleList=" + currentBubbleList + + " }"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeBoolean(expandedChanged); + parcel.writeBoolean(expanded); + parcel.writeString(selectedBubbleKey); + parcel.writeParcelable(addedBubble, flags); + parcel.writeParcelable(updatedBubble, flags); + parcel.writeString(suppressedBubbleKey); + parcel.writeString(unsupressedBubbleKey); + parcel.writeParcelableList(removedBubbles, flags); + parcel.writeStringList(bubbleKeysInOrder); + parcel.writeParcelableList(currentBubbleList, flags); + } + + @NonNull + public static final Creator<BubbleBarUpdate> CREATOR = + new Creator<BubbleBarUpdate>() { + public BubbleBarUpdate createFromParcel(Parcel source) { + return new BubbleBarUpdate(source); + } + public BubbleBarUpdate[] newArray(int size) { + return new BubbleBarUpdate[size]; + } + }; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java new file mode 100644 index 000000000000..b0dea7231a1e --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common.bubbles; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Notification; +import android.graphics.drawable.Icon; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Contains information necessary to present a bubble. + */ +public class BubbleInfo implements Parcelable { + + // TODO(b/269672147): needs a title string for a11y & that comes from notification + // TODO(b/269671451): needs whether the bubble is an 'important person' or not + + private String mKey; // Same key as the Notification + private int mFlags; // Flags from BubbleMetadata + private String mShortcutId; + private int mUserId; + private String mPackageName; + /** + * All notification bubbles require a shortcut to be set on the notification, however, the + * app could still specify an Icon and PendingIntent to use for the bubble. In that case + * this icon will be populated. If the bubble is entirely shortcut based, this will be null. + */ + @Nullable + private Icon mIcon; + + public BubbleInfo(String key, int flags, String shortcutId, @Nullable Icon icon, + int userId, String packageName) { + mKey = key; + mFlags = flags; + mShortcutId = shortcutId; + mIcon = icon; + mUserId = userId; + mPackageName = packageName; + } + + public BubbleInfo(Parcel source) { + mKey = source.readString(); + mFlags = source.readInt(); + mShortcutId = source.readString(); + mIcon = source.readTypedObject(Icon.CREATOR); + mUserId = source.readInt(); + mPackageName = source.readString(); + } + + public String getKey() { + return mKey; + } + + public String getShortcutId() { + return mShortcutId; + } + + public Icon getIcon() { + return mIcon; + } + + public int getFlags() { + return mFlags; + } + + public int getUserId() { + return mUserId; + } + + public String getPackageName() { + return mPackageName; + } + + /** + * Whether this bubble is currently being hidden from the stack. + */ + public boolean isBubbleSuppressed() { + return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE) != 0; + } + + /** + * Whether this bubble is able to be suppressed (i.e. has the developer opted into the API + * to + * hide the bubble when in the same content). + */ + public boolean isBubbleSuppressable() { + return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE) != 0; + } + + /** + * Whether the notification for this bubble is hidden from the shade. + */ + public boolean isNotificationSuppressed() { + return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION) != 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BubbleInfo)) return false; + BubbleInfo bubble = (BubbleInfo) o; + return Objects.equals(mKey, bubble.mKey); + } + + @Override + public int hashCode() { + return mKey.hashCode(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mKey); + parcel.writeInt(mFlags); + parcel.writeString(mShortcutId); + parcel.writeTypedObject(mIcon, flags); + parcel.writeInt(mUserId); + parcel.writeString(mPackageName); + } + + @NonNull + public static final Creator<BubbleInfo> CREATOR = + new Creator<BubbleInfo>() { + public BubbleInfo createFromParcel(Parcel source) { + return new BubbleInfo(source); + } + + public BubbleInfo[] newArray(int size) { + return new BubbleInfo[size]; + } + }; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RemovedBubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RemovedBubble.java new file mode 100644 index 000000000000..f90591b84b7e --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RemovedBubble.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common.bubbles; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents a removed bubble, defining the key and reason the bubble was removed. + */ +public class RemovedBubble implements Parcelable { + + private final String mKey; + private final int mRemovalReason; + + public RemovedBubble(String key, int removalReason) { + mKey = key; + mRemovalReason = removalReason; + } + + public RemovedBubble(Parcel parcel) { + mKey = parcel.readString(); + mRemovalReason = parcel.readInt(); + } + + public String getKey() { + return mKey; + } + + public int getRemovalReason() { + return mRemovalReason; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mKey); + dest.writeInt(mRemovalReason); + } + + @NonNull + public static final Creator<RemovedBubble> CREATOR = + new Creator<RemovedBubble>() { + public RemovedBubble createFromParcel(Parcel source) { + return new RemovedBubble(source); + } + public RemovedBubble[] newArray(int size) { + return new RemovedBubble[size]; + } + }; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 57b5b8f24fad..9808c591592f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -32,9 +32,6 @@ import com.android.wm.shell.R; import com.android.wm.shell.RootDisplayAreaOrganizer; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.TaskViewFactory; -import com.android.wm.shell.TaskViewFactoryController; -import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.back.BackAnimation; @@ -93,6 +90,9 @@ import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.sysui.ShellInterface; +import com.android.wm.shell.taskview.TaskViewFactory; +import com.android.wm.shell.taskview.TaskViewFactoryController; +import com.android.wm.shell.taskview.TaskViewTransitions; import com.android.wm.shell.transition.ShellTransitions; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index f8743ed23aaa..e2cd7a0d1d77 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -30,7 +30,6 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.bubbles.BubbleData; @@ -89,6 +88,7 @@ import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.taskview.TaskViewTransitions; import com.android.wm.shell.transition.DefaultMixedHandler; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index c5fc879039cb..f2f30ea7a286 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -1176,20 +1176,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final Rect newDestinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); if (newDestinationBounds.equals(currentDestinationBounds)) return; - if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) { - if (mWaitForFixedRotation) { - // The new destination bounds are in next rotation (DisplayLayout has been rotated - // in computeRotatedBounds). The animation runs in previous rotation so the end - // bounds need to be transformed. - final Rect displayBounds = mPipBoundsState.getDisplayBounds(); - final Rect rotatedEndBounds = new Rect(newDestinationBounds); - rotateBounds(rotatedEndBounds, displayBounds, mNextRotation, mCurrentRotation); - animator.updateEndValue(rotatedEndBounds); - } else { - animator.updateEndValue(newDestinationBounds); - } - } - animator.setDestinationBounds(newDestinationBounds); + updateAnimatorBounds(newDestinationBounds); destinationBoundsOut.set(newDestinationBounds); } @@ -1201,7 +1188,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mPipAnimationController.getCurrentAnimator(); if (animator != null && animator.isRunning()) { if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) { - animator.updateEndValue(bounds); + if (mWaitForFixedRotation) { + // The new destination bounds are in next rotation (DisplayLayout has been + // rotated in computeRotatedBounds). The animation runs in previous rotation so + // the end bounds need to be transformed. + final Rect displayBounds = mPipBoundsState.getDisplayBounds(); + final Rect rotatedEndBounds = new Rect(bounds); + rotateBounds(rotatedEndBounds, displayBounds, mNextRotation, mCurrentRotation); + animator.updateEndValue(rotatedEndBounds); + } else { + animator.updateEndValue(bounds); + } } animator.setDestinationBounds(bounds); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java new file mode 100644 index 000000000000..0221db836dda --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip.tv; + +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_ALL_ACTIONS_MENU; +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_MOVE_MENU; +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_NO_MENU; + +import android.content.Context; +import android.content.res.Resources; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.R; +import com.android.wm.shell.protolog.ShellProtoLogGroup; + +/** + * This view is part of the Tv PiP menu. It is drawn behind the PiP surface and serves as a + * background behind the PiP content. If the PiP content is translucent, this view is visible + * behind it. + * It is also used to draw the shadow behind the Tv PiP menu. The shadow intensity is determined + * by the menu mode that the Tv PiP menu is in. See {@link TvPipMenuController.TvPipMenuMode}. + */ +class TvPipBackgroundView extends FrameLayout { + private static final String TAG = "TvPipBackgroundView"; + + private final View mBackgroundView; + private final int mElevationNoMenu; + private final int mElevationMoveMenu; + private final int mElevationAllActionsMenu; + private final int mPipMenuFadeAnimationDuration; + + private @TvPipMenuController.TvPipMenuMode int mCurrentMenuMode = MODE_NO_MENU; + + TvPipBackgroundView(@NonNull Context context) { + super(context, null, 0, 0); + inflate(context, R.layout.tv_pip_menu_background, this); + + mBackgroundView = findViewById(R.id.background_view); + + final Resources res = mContext.getResources(); + mElevationNoMenu = res.getDimensionPixelSize(R.dimen.pip_menu_elevation_no_menu); + mElevationMoveMenu = res.getDimensionPixelSize(R.dimen.pip_menu_elevation_move_menu); + mElevationAllActionsMenu = + res.getDimensionPixelSize(R.dimen.pip_menu_elevation_all_actions_menu); + mPipMenuFadeAnimationDuration = + res.getInteger(R.integer.tv_window_menu_fade_animation_duration); + } + + void transitionToMenuMode(@TvPipMenuController.TvPipMenuMode int pipMenuMode) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: transitionToMenuMode(), old menu mode = %s, new menu mode = %s", + TAG, TvPipMenuController.getMenuModeString(mCurrentMenuMode), + TvPipMenuController.getMenuModeString(pipMenuMode)); + + if (mCurrentMenuMode == pipMenuMode) return; + + int elevation = mElevationNoMenu; + Interpolator interpolator = TvPipInterpolators.ENTER; + switch(pipMenuMode) { + case MODE_NO_MENU: + elevation = mElevationNoMenu; + interpolator = TvPipInterpolators.EXIT; + break; + case MODE_MOVE_MENU: + elevation = mElevationMoveMenu; + break; + case MODE_ALL_ACTIONS_MENU: + elevation = mElevationAllActionsMenu; + if (mCurrentMenuMode == MODE_MOVE_MENU) { + interpolator = TvPipInterpolators.EXIT; + } + break; + default: + throw new IllegalArgumentException( + "Unknown TV PiP menu mode: " + pipMenuMode); + } + + mBackgroundView.animate() + .translationZ(elevation) + .setInterpolator(interpolator) + .setDuration(mPipMenuFadeAnimationDuration) + .start(); + + mCurrentMenuMode = pipMenuMode; + } + +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java index 49d40d3c2611..bca27a5c6636 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java @@ -86,6 +86,7 @@ public class TvPipCustomAction extends TvPipAction { Bundle extras = new Bundle(); extras.putCharSequence(Notification.EXTRA_PICTURE_CONTENT_DESCRIPTION, mRemoteAction.getContentDescription()); + extras.putBoolean(Notification.EXTRA_CONTAINS_CUSTOM_VIEW, true); builder.addExtras(extras); builder.setSemanticAction(isCloseAction() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java index 73123b153382..be1f800b9d2e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java @@ -18,7 +18,7 @@ package com.android.wm.shell.pip.tv; import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP; -import android.app.ActivityManager; +import android.annotation.IntDef; import android.app.RemoteAction; import android.content.BroadcastReceiver; import android.content.Context; @@ -27,7 +27,6 @@ import android.content.IntentFilter; import android.graphics.Insets; import android.graphics.Rect; import android.os.Handler; -import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; @@ -36,6 +35,7 @@ import android.window.SurfaceSyncGroup; import androidx.annotation.Nullable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; import com.android.wm.shell.common.SystemWindows; @@ -60,14 +60,37 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis private Delegate mDelegate; private SurfaceControl mLeash; private TvPipMenuView mPipMenuView; - private View mPipBackgroundView; + private TvPipBackgroundView mPipBackgroundView; + private boolean mMenuIsFocused; - private boolean mMenuIsOpen; - // User can actively move the PiP via the DPAD. - private boolean mInMoveMode; - // Used when only showing the move menu since we want to close the menu completely when - // exiting the move menu instead of showing the regular button menu. - private boolean mCloseAfterExitMoveMenu; + @TvPipMenuMode + private int mCurrentMenuMode = MODE_NO_MENU; + @TvPipMenuMode + private int mPrevMenuMode = MODE_NO_MENU; + + @IntDef(prefix = { "MODE_" }, value = { + MODE_NO_MENU, + MODE_MOVE_MENU, + MODE_ALL_ACTIONS_MENU, + }) + public @interface TvPipMenuMode {} + + /** + * In this mode the PiP menu is not focused and no user controls are displayed. + */ + static final int MODE_NO_MENU = 0; + + /** + * In this mode the PiP menu is focused and the user can use the DPAD controls to move the PiP + * to a different position on the screen. We draw arrows in all possible movement directions. + */ + static final int MODE_MOVE_MENU = 1; + + /** + * In this mode the PiP menu is focused and we display an array of actions that the user can + * select. See {@link TvPipActionsProvider} for the types of available actions. + */ + static final int MODE_ALL_ACTIONS_MENU = 2; public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState, SystemWindows systemWindows, Handler mainHandler) { @@ -143,18 +166,27 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis "%s: Actions provider is not set", TAG); return; } - mPipMenuView = new TvPipMenuView(mContext, mMainHandler, this, mTvPipActionsProvider); + mPipMenuView = createTvPipMenuView(); setUpViewSurfaceZOrder(mPipMenuView, 1); addPipMenuViewToSystemWindows(mPipMenuView, MENU_WINDOW_TITLE); } + @VisibleForTesting + TvPipMenuView createTvPipMenuView() { + return new TvPipMenuView(mContext, mMainHandler, this, mTvPipActionsProvider); + } + private void attachPipBackgroundView() { - mPipBackgroundView = LayoutInflater.from(mContext) - .inflate(R.layout.tv_pip_menu_background, null); + mPipBackgroundView = createTvPipBackgroundView(); setUpViewSurfaceZOrder(mPipBackgroundView, -1); addPipMenuViewToSystemWindows(mPipBackgroundView, BACKGROUND_WINDOW_TITLE); } + @VisibleForTesting + TvPipBackgroundView createTvPipBackgroundView() { + return new TvPipBackgroundView(mContext); + } + private void setUpViewSurfaceZOrder(View v, int zOrderRelativeToPip) { v.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override @@ -188,37 +220,14 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis void showMovementMenu() { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: showMovementMenuOnly()", TAG); - setInMoveMode(true); - if (mMenuIsOpen) { - mPipMenuView.showMoveMenu(mTvPipBoundsState.getTvPipGravity()); - } else { - mCloseAfterExitMoveMenu = true; - showMenuInternal(); - } + "%s: showMovementMenu()", TAG); + switchToMenuMode(MODE_MOVE_MENU); } @Override public void showMenu() { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMenu()", TAG); - setInMoveMode(false); - mCloseAfterExitMoveMenu = false; - showMenuInternal(); - } - - private void showMenuInternal() { - if (mPipMenuView == null) { - return; - } - - mMenuIsOpen = true; - grantPipMenuFocus(true); - if (mInMoveMode) { - mPipMenuView.showMoveMenu(mTvPipBoundsState.getTvPipGravity()); - } else { - mPipMenuView.showButtonsMenu(/* exitingMoveMode= */ false); - } - mPipMenuView.updateBounds(mTvPipBoundsState.getBounds()); + switchToMenuMode(MODE_ALL_ACTIONS_MENU, true); } void onPipTransitionToTargetBoundsStarted(Rect targetBounds) { @@ -228,9 +237,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } void updateGravity(int gravity) { - if (mInMoveMode) { - mPipMenuView.showMovementHints(gravity); - } + mPipMenuView.setPipGravity(gravity); } private Rect calculateMenuSurfaceBounds(Rect pipBounds) { @@ -240,58 +247,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis void closeMenu() { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: closeMenu()", TAG); - - if (mPipMenuView == null) { - return; - } - - mMenuIsOpen = false; - mPipMenuView.hideAllUserControls(); - grantPipMenuFocus(false); - mDelegate.onMenuClosed(); - } - - boolean isInMoveMode() { - return mInMoveMode; - } - - private void setInMoveMode(boolean moveMode) { - if (mInMoveMode == moveMode) { - return; - } - mInMoveMode = moveMode; - if (mDelegate != null) { - mDelegate.onInMoveModeChanged(); - } - } - - @Override - public boolean onExitMoveMode() { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: onExitMoveMode - %b, close when exiting move menu: %b", - TAG, mInMoveMode, mCloseAfterExitMoveMenu); - - if (mInMoveMode) { - setInMoveMode(false); - if (mCloseAfterExitMoveMenu) { - mCloseAfterExitMoveMenu = false; - closeMenu(); - } else { - mPipMenuView.showButtonsMenu(/* exitingMoveMode= */ true); - } - return true; - } - return false; - } - - @Override - public boolean onPipMovement(int keycode) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: onPipMovement - %b", TAG, mInMoveMode); - if (mInMoveMode) { - mDelegate.movePip(keycode); - } - return mInMoveMode; + switchToMenuMode(MODE_NO_MENU); } @Override @@ -422,13 +378,91 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height())); if (mPipMenuView != null) { - mPipMenuView.updateBounds(pipBounds); + mPipMenuView.setPipBounds(pipBounds); + } + } + + // Start methods handling {@link TvPipMenuMode} + + @VisibleForTesting + boolean isMenuOpen() { + return mCurrentMenuMode != MODE_NO_MENU; + } + + @VisibleForTesting + boolean isInMoveMode() { + return mCurrentMenuMode == MODE_MOVE_MENU; + } + + @VisibleForTesting + boolean isInAllActionsMode() { + return mCurrentMenuMode == MODE_ALL_ACTIONS_MENU; + } + + private void switchToMenuMode(@TvPipMenuMode int menuMode) { + switchToMenuMode(menuMode, false); + } + + private void switchToMenuMode(@TvPipMenuMode int menuMode, boolean resetMenu) { + // Note: we intentionally don't return early here, because the TvPipMenuView needs to + // refresh the Ui even if there is no menu mode change. + mPrevMenuMode = mCurrentMenuMode; + mCurrentMenuMode = menuMode; + + ProtoLog.i(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: switchToMenuMode: setting mCurrentMenuMode=%s, mPrevMenuMode=%s", TAG, + getMenuModeString(), getMenuModeString(mPrevMenuMode)); + + updateUiOnNewMenuModeRequest(resetMenu); + updateDelegateOnNewMenuModeRequest(); + } + + private void updateUiOnNewMenuModeRequest(boolean resetMenu) { + if (mPipMenuView == null || mPipBackgroundView == null) return; + + mPipMenuView.setPipGravity(mTvPipBoundsState.getTvPipGravity()); + mPipMenuView.transitionToMenuMode(mCurrentMenuMode, resetMenu); + mPipBackgroundView.transitionToMenuMode(mCurrentMenuMode); + grantPipMenuFocus(mCurrentMenuMode != MODE_NO_MENU); + } + + private void updateDelegateOnNewMenuModeRequest() { + if (mPrevMenuMode == mCurrentMenuMode) return; + if (mDelegate == null) return; + + if (mPrevMenuMode == MODE_MOVE_MENU || isInMoveMode()) { + mDelegate.onInMoveModeChanged(); } + + if (mCurrentMenuMode == MODE_NO_MENU) { + mDelegate.onMenuClosed(); + } + } + + @VisibleForTesting + String getMenuModeString() { + return getMenuModeString(mCurrentMenuMode); } + static String getMenuModeString(@TvPipMenuMode int menuMode) { + switch(menuMode) { + case MODE_NO_MENU: + return "MODE_NO_MENU"; + case MODE_MOVE_MENU: + return "MODE_MOVE_MENU"; + case MODE_ALL_ACTIONS_MENU: + return "MODE_ALL_ACTIONS_MENU"; + default: + return "Unknown"; + } + } + + // Start {@link TvPipMenuView.Delegate} methods + @Override - public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: onFocusTaskChanged", TAG); + public void onCloseEduText() { + mTvPipBoundsState.setPipMenuTemporaryDecorInsets(Insets.NONE); + mDelegate.closeEduText(); } @Override @@ -439,9 +473,35 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } @Override - public void onCloseEduText() { - mTvPipBoundsState.setPipMenuTemporaryDecorInsets(Insets.NONE); - mDelegate.closeEduText(); + public boolean onExitMoveMode() { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: onExitMoveMode - mCurrentMenuMode=%s", TAG, getMenuModeString()); + + final int saveMenuMode = mCurrentMenuMode; + if (isInMoveMode()) { + switchToMenuMode(mPrevMenuMode); + } + return saveMenuMode == MODE_MOVE_MENU; + } + + @Override + public boolean onPipMovement(int keycode) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: onPipMovement - mCurrentMenuMode=%s", TAG, getMenuModeString()); + if (isInMoveMode()) { + mDelegate.movePip(keycode); + } + return isInMoveMode(); + } + + @Override + public void onPipWindowFocusChanged(boolean focused) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: onPipWindowFocusChanged - focused=%b", TAG, focused); + mMenuIsFocused = focused; + if (!focused && isMenuOpen()) { + closeMenu(); + } } interface Delegate { @@ -455,6 +515,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } private void grantPipMenuFocus(boolean grantFocus) { + if (mMenuIsFocused == grantFocus) return; + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: grantWindowFocus(%b)", TAG, grantFocus); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java index 56c602a1d4f3..ccf65c299613 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java @@ -26,6 +26,9 @@ import static android.view.KeyEvent.KEYCODE_DPAD_UP; import static android.view.KeyEvent.KEYCODE_ENTER; import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_MOVE; +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_ALL_ACTIONS_MENU; +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_MOVE_MENU; +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_NO_MENU; import android.content.Context; import android.graphics.Rect; @@ -86,9 +89,9 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L private final ImageView mArrowLeft; private final TvWindowMenuActionButton mA11yDoneButton; - private Rect mCurrentPipBounds; - private boolean mMoveMenuIsVisible; - private boolean mButtonMenuIsVisible; + private @TvPipMenuController.TvPipMenuMode int mCurrentMenuMode = MODE_NO_MENU; + private final Rect mCurrentPipBounds = new Rect(); + private int mCurrentPipGravity; private boolean mSwitchingOrientation; private final AccessibilityManager mA11yManager; @@ -172,7 +175,7 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L return; } - if (mButtonMenuIsVisible) { + if (mCurrentMenuMode == MODE_ALL_ACTIONS_MENU) { mSwitchingOrientation = true; mActionButtonsRecyclerView.animate() .alpha(0) @@ -217,19 +220,14 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L /** * Also updates the button gravity. */ - void updateBounds(Rect updatedBounds) { + void setPipBounds(Rect updatedPipBounds) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: updateLayout, width: %s, height: %s", TAG, updatedBounds.width(), - updatedBounds.height()); - mCurrentPipBounds = updatedBounds; - updatePipFrameBounds(); - } + "%s: updateLayout, width: %s, height: %s", TAG, updatedPipBounds.width(), + updatedPipBounds.height()); + if (updatedPipBounds.equals(mCurrentPipBounds)) return; - Rect getPipMenuContainerBounds(Rect pipBounds) { - final Rect menuUiBounds = new Rect(pipBounds); - menuUiBounds.inset(-mPipMenuOuterSpace, -mPipMenuOuterSpace); - menuUiBounds.bottom += mEduTextDrawer.getHeight(); - return menuUiBounds; + mCurrentPipBounds.set(updatedPipBounds); + updatePipFrameBounds(); } /** @@ -264,12 +262,39 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L } } - /** - * @param gravity for the arrow hints - */ - void showMoveMenu(int gravity) { + Rect getPipMenuContainerBounds(Rect pipBounds) { + final Rect menuUiBounds = new Rect(pipBounds); + menuUiBounds.inset(-mPipMenuOuterSpace, -mPipMenuOuterSpace); + menuUiBounds.bottom += mEduTextDrawer.getHeight(); + return menuUiBounds; + } + + void transitionToMenuMode(int menuMode, boolean resetMenu) { + switch (menuMode) { + case MODE_NO_MENU: + hideAllUserControls(); + break; + case MODE_MOVE_MENU: + showMoveMenu(); + break; + case MODE_ALL_ACTIONS_MENU: + showAllActionsMenu(resetMenu); + break; + default: + throw new IllegalArgumentException( + "Unknown TV PiP menu mode: " + + TvPipMenuController.getMenuModeString(mCurrentMenuMode)); + } + + mCurrentMenuMode = menuMode; + } + + private void showMoveMenu() { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMoveMenu()", TAG); - showMovementHints(gravity); + + if (mCurrentMenuMode == MODE_MOVE_MENU) return; + + showMovementHints(); setMenuButtonsVisible(false); setFrameHighlighted(true); @@ -278,32 +303,38 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L mEduTextDrawer.closeIfNeeded(); } - - void showButtonsMenu(boolean exitingMoveMode) { + private void showAllActionsMenu(boolean resetMenu) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: showButtonsMenu(), exitingMoveMode %b", TAG, exitingMoveMode); + "%s: showAllActionsMenu(), resetMenu %b", TAG, resetMenu); + + if (resetMenu) { + scrollToFirstAction(); + } + + if (mCurrentMenuMode == MODE_ALL_ACTIONS_MENU) return; + setMenuButtonsVisible(true); hideMovementHints(); setFrameHighlighted(true); animateAlphaTo(1f, mDimLayer); mEduTextDrawer.closeIfNeeded(); - if (exitingMoveMode) { - scrollAndRefocusButton(mTvPipActionsProvider.getFirstIndexOfAction(ACTION_MOVE), - /* alwaysScroll= */ false); - } else { - scrollAndRefocusButton(0, /* alwaysScroll= */ true); + if (mCurrentMenuMode == MODE_MOVE_MENU) { + refocusButton(mTvPipActionsProvider.getFirstIndexOfAction(ACTION_MOVE)); } - } - private void scrollAndRefocusButton(int position, boolean alwaysScroll) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: scrollAndRefocusButton, target: %d", TAG, position); + } - if (alwaysScroll || !refocusButton(position)) { - mButtonLayoutManager.scrollToPositionWithOffset(position, 0); - mActionButtonsRecyclerView.post(() -> refocusButton(position)); + private void scrollToFirstAction() { + // Clearing the focus here is necessary to allow a smooth scroll even if the first action + // is currently not visible. + final View focusedChild = mActionButtonsRecyclerView.getFocusedChild(); + if (focusedChild != null) { + focusedChild.clearFocus(); } + + mButtonLayoutManager.scrollToPosition(0); + mActionButtonsRecyclerView.post(() -> refocusButton(0)); } /** @@ -311,6 +342,9 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L * the view for the position not being available (scrolling beforehand will be necessary). */ private boolean refocusButton(int position) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: refocusButton, position: %d", TAG, position); + View itemToFocus = mButtonLayoutManager.findViewByPosition(position); if (itemToFocus != null) { itemToFocus.requestFocus(); @@ -319,21 +353,29 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L return itemToFocus != null; } - void hideAllUserControls() { + private void hideAllUserControls() { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: hideAllUserControls()", TAG); + + if (mCurrentMenuMode == MODE_NO_MENU) return; + setMenuButtonsVisible(false); hideMovementHints(); setFrameHighlighted(false); animateAlphaTo(0f, mDimLayer); } + void setPipGravity(int gravity) { + mCurrentPipGravity = gravity; + if (mCurrentMenuMode == MODE_MOVE_MENU) { + showMovementHints(); + } + } + @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); - if (!hasWindowFocus) { - hideAllUserControls(); - } + mListener.onPipWindowFocusChanged(hasWindowFocus); } private void animateAlphaTo(float alpha, View view) { @@ -399,15 +441,13 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L /** * Shows user hints for moving the PiP, e.g. arrows. */ - public void showMovementHints(int gravity) { + public void showMovementHints() { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: showMovementHints(), position: %s", TAG, Gravity.toString(gravity)); - mMoveMenuIsVisible = true; - - animateAlphaTo(checkGravity(gravity, Gravity.BOTTOM) ? 1f : 0f, mArrowUp); - animateAlphaTo(checkGravity(gravity, Gravity.TOP) ? 1f : 0f, mArrowDown); - animateAlphaTo(checkGravity(gravity, Gravity.RIGHT) ? 1f : 0f, mArrowLeft); - animateAlphaTo(checkGravity(gravity, Gravity.LEFT) ? 1f : 0f, mArrowRight); + "%s: showMovementHints(), position: %s", TAG, Gravity.toString(mCurrentPipGravity)); + animateAlphaTo(checkGravity(mCurrentPipGravity, Gravity.BOTTOM) ? 1f : 0f, mArrowUp); + animateAlphaTo(checkGravity(mCurrentPipGravity, Gravity.TOP) ? 1f : 0f, mArrowDown); + animateAlphaTo(checkGravity(mCurrentPipGravity, Gravity.RIGHT) ? 1f : 0f, mArrowLeft); + animateAlphaTo(checkGravity(mCurrentPipGravity, Gravity.LEFT) ? 1f : 0f, mArrowRight); boolean a11yEnabled = mA11yManager.isEnabled(); setArrowA11yEnabled(mArrowUp, a11yEnabled, KEYCODE_DPAD_UP); @@ -446,10 +486,7 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: hideMovementHints()", TAG); - if (!mMoveMenuIsVisible) { - return; - } - mMoveMenuIsVisible = false; + if (mCurrentMenuMode != MODE_MOVE_MENU) return; animateAlphaTo(0, mArrowUp); animateAlphaTo(0, mArrowRight); @@ -464,7 +501,6 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L private void setMenuButtonsVisible(boolean visible) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showUserActions: %b", TAG, visible); - mButtonMenuIsVisible = visible; animateAlphaTo(visible ? 1 : 0, mActionButtonsRecyclerView); } @@ -534,5 +570,11 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L * @return whether pip movement was handled. */ boolean onPipMovement(int keycode); + + /** + * Called when the TvPipMenuView loses focus. This also means that the TV PiP menu window + * has lost focus. + */ + void onPipWindowFocusChanged(boolean focused); } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index db75be75788a..5c64177ae835 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -418,6 +418,13 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); + if (taskInfo != null + && taskInfo.configuration.windowConfiguration.isAlwaysOnTop()) { + // Tasks that are always on top (e.g. bubbles), will handle their own transition + // as they are on top of everything else. So cancel the merge here. + cancel(); + return; + } hasTaskChange = hasTaskChange || taskInfo != null; final boolean isLeafTask = leafTaskFilter.test(change); if (TransitionUtil.isOpeningType(change.getMode())) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java index ebdaaa9aa4a9..32abd7312109 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java @@ -212,7 +212,7 @@ class SplitScreenTransitions { } } - void applyResizeTransition(@NonNull IBinder transition, @NonNull TransitionInfo info, + void playResizeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 33cbdac67061..c61658774459 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -2376,7 +2376,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } } else if (mSplitTransitions.isPendingResize(transition)) { - mSplitTransitions.applyResizeTransition(transition, info, startTransaction, + mSplitTransitions.playResizeAnimation(transition, info, startTransaction, finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token, mMainStage.getSplitDecorManager(), mSideStage.getSplitDecorManager()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index d6f4d6daaa83..ead0bcd15c73 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -267,9 +267,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { return; } sendStatusChanged(); - } else { - throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo - + "\n mRootTaskInfo: " + mRootTaskInfo); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java index bdda6a8e926b..bfa63909cd47 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java @@ -22,6 +22,8 @@ package com.android.wm.shell.sysui; public class ShellSharedConstants { // See IPip.aidl public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip"; + // See IBubbles.aidl + public static final String KEY_EXTRA_SHELL_BUBBLES = "extra_shell_bubbles"; // See ISplitScreen.aidl public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen"; // See IOneHanded.aidl diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java index 7a6aec718006..e4d8c32eb5c8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.taskview; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewBase.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewBase.java index 3d0a8fd83819..5fdb60d2d342 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewBase.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewBase.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.taskview; import android.app.ActivityManager; import android.graphics.Rect; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactory.java index a29e7a085a21..a7e4b0119480 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactory.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.taskview; import android.annotation.UiContext; import android.content.Context; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactoryController.java index 735d9bce2059..7eed5883043d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactoryController.java @@ -14,11 +14,12 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.taskview; import android.annotation.UiContext; import android.content.Context; +import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.annotations.ExternalThread; @@ -51,6 +52,9 @@ public class TaskViewFactoryController { mTaskViewTransitions = null; } + /** + * @return the underlying {@link TaskViewFactory}. + */ public TaskViewFactory asTaskViewFactory() { return mImpl; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java index 080b171f4d40..36c9077a197b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTaskController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.taskview; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; @@ -35,6 +35,7 @@ import android.view.SurfaceControl; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; +import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SyncTransactionQueue; import java.io.PrintWriter; @@ -386,8 +387,15 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { return; } // Sync Transactions can't operate simultaneously with shell transition collection. - // The transition animation (upon showing) will sync the location itself. - if (isUsingShellTransitions() && mTaskViewTransitions.hasPending()) return; + if (isUsingShellTransitions()) { + if (mTaskViewTransitions.hasPending()) { + // There is already a transition in-flight. The window bounds will be synced + // once it is complete. + return; + } + mTaskViewTransitions.setTaskBounds(this, boundsOnScreen); + return; + } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mTaskToken, boundsOnScreen); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java index 306d6196c553..3b1ce49ebdc7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java @@ -14,8 +14,9 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.taskview; +import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -23,6 +24,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.graphics.Rect; import android.os.IBinder; import android.util.Slog; import android.view.SurfaceControl; @@ -40,7 +42,7 @@ import java.util.ArrayList; * Handles Shell Transitions that involve TaskView tasks. */ public class TaskViewTransitions implements Transitions.TransitionHandler { - private static final String TAG = "TaskViewTransitions"; + static final String TAG = "TaskViewTransitions"; private final ArrayList<TaskViewTaskController> mTaskViews = new ArrayList<>(); private final ArrayList<PendingTransition> mPending = new ArrayList<>(); @@ -197,6 +199,13 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { // visibility is reported in transition. } + void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen) { + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setBounds(taskView.getTaskInfo().token, boundsOnScreen); + mPending.add(new PendingTransition(TRANSIT_CHANGE, wct, taskView, null /* cookie */)); + startNextTransition(); + } + private void startNextTransition() { if (mPending.isEmpty()) return; final PendingTransition pending = mPending.get(0); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java index e632b56d5e54..d25318df6b6a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java @@ -228,7 +228,7 @@ class ScreenRotationAnimation { } else if ((mEndWidth > mStartWidth) == (mEndHeight > mStartHeight) && (mEndWidth != mStartWidth || mEndHeight != mStartHeight)) { // Display resizes without rotation change. - final float scale = Math.max((float) mEndWidth / mStartHeight, + final float scale = Math.max((float) mEndWidth / mStartWidth, (float) mEndHeight / mStartHeight); matrix.setScale(scale, scale); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index f943e52e59a2..c0dcd0b68c6f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -26,16 +26,20 @@ import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.content.Context; +import android.content.res.Resources; import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.util.DisplayMetrics; import android.util.SparseArray; import android.view.Choreographer; import android.view.InputChannel; @@ -541,9 +545,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { if (ev.getY() > statusBarHeight) { if (DesktopModeStatus.isProto2Enabled()) { mPauseRelayoutForTask = relevantDecor.mTaskInfo.taskId; - mDesktopTasksController.ifPresent( - c -> c.moveToDesktopWithAnimation(relevantDecor.mTaskInfo, - getFreeformBounds(ev))); + centerAndMoveToDesktopWithAnimation(relevantDecor, ev); } else if (DesktopModeStatus.isProto1Enabled()) { mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true)); } @@ -596,25 +598,59 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } - private Rect getFreeformBounds(@NonNull MotionEvent ev) { - final Rect endBounds = new Rect(); - final int finalWidth = (int) (FINAL_FREEFORM_SCALE - * mDragToDesktopAnimationStartBounds.width()); - final int finalHeight = (int) (FINAL_FREEFORM_SCALE - * mDragToDesktopAnimationStartBounds.height()); - - endBounds.left = mDragToDesktopAnimationStartBounds.centerX() - finalWidth / 2 - + (int) (ev.getX() - mCaptionDragStartX); - endBounds.right = endBounds.left + (int) (FINAL_FREEFORM_SCALE - * mDragToDesktopAnimationStartBounds.width()); - endBounds.top = (int) (ev.getY() - - ((FINAL_FREEFORM_SCALE - DRAG_FREEFORM_SCALE) - * mDragToDesktopAnimationStartBounds.height() / 2)); - endBounds.bottom = endBounds.top + finalHeight; - + /** + * Gets bounds of a scaled window centered relative to the screen bounds + * @param scale the amount to scale to relative to the Screen Bounds + */ + private Rect calculateFreeformBounds(float scale) { + final Resources resources = mContext.getResources(); + final DisplayMetrics metrics = resources.getDisplayMetrics(); + final int screenWidth = metrics.widthPixels; + final int screenHeight = metrics.heightPixels; + + final float adjustmentPercentage = (1f - scale) / 2; + final Rect endBounds = new Rect((int) (screenWidth * adjustmentPercentage), + (int) (screenHeight * adjustmentPercentage), + (int) (screenWidth * (adjustmentPercentage + scale)), + (int) (screenHeight * (adjustmentPercentage + scale))); return endBounds; } + /** + * Animates a window to the center, grows to freeform size, and transitions to Desktop Mode. + * @param relevantDecor the window decor of the task to be animated + * @param ev the motion event that triggers the animation + */ + private void centerAndMoveToDesktopWithAnimation(DesktopModeWindowDecoration relevantDecor, + MotionEvent ev) { + ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); + animator.setDuration(FREEFORM_ANIMATION_DURATION); + final SurfaceControl sc = relevantDecor.mTaskSurface; + final Rect endBounds = calculateFreeformBounds(DRAG_FREEFORM_SCALE); + final Transaction t = mTransactionFactory.get(); + final float diffX = endBounds.centerX() - ev.getX(); + final float diffY = endBounds.top - ev.getY(); + final float startingX = ev.getX() - DRAG_FREEFORM_SCALE + * mDragToDesktopAnimationStartBounds.width() / 2; + + animator.addUpdateListener(animation -> { + final float animatorValue = (float) animation.getAnimatedValue(); + final float x = startingX + diffX * animatorValue; + final float y = ev.getY() + diffY * animatorValue; + t.setPosition(sc, x, y); + t.apply(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mDesktopTasksController.ifPresent( + c -> c.moveToDesktopWithAnimation(relevantDecor.mTaskInfo, + calculateFreeformBounds(FINAL_FREEFORM_SCALE))); + } + }); + animator.start(); + } + private void startAnimation(@NonNull DesktopModeWindowDecoration focusedDecor) { mDragToDesktopValueAnimator = ValueAnimator.ofFloat(1f, DRAG_FREEFORM_SCALE); mDragToDesktopValueAnimator.setDuration(FREEFORM_ANIMATION_DURATION); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 6478fe723027..e08d40d76c16 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -17,15 +17,20 @@ package com.android.wm.shell.windowdecor; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import android.app.ActivityManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; +import android.graphics.drawable.Drawable; import android.os.Handler; import android.util.Log; import android.view.Choreographer; @@ -33,11 +38,13 @@ import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import android.window.WindowContainerTransaction; +import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; @@ -69,17 +76,20 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private DragDetector mDragDetector; private RelayoutParams mRelayoutParams = new RelayoutParams(); - private final int mCaptionMenuHeightId = R.dimen.freeform_decor_caption_menu_height; - private final int mCaptionMenuHeightWithoutWindowingControlsId = - R.dimen.freeform_decor_caption_menu_height_no_windowing_controls; private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult = new WindowDecoration.RelayoutResult<>(); - private AdditionalWindow mHandleMenu; - private final int mHandleMenuWidthId = R.dimen.freeform_decor_caption_menu_width; - private final int mHandleMenuShadowRadiusId = R.dimen.caption_menu_shadow_radius; - private final int mHandleMenuCornerRadiusId = R.dimen.caption_menu_corner_radius; - private PointF mHandleMenuPosition = new PointF(); + private final PointF mHandleMenuAppInfoPillPosition = new PointF(); + private final PointF mHandleMenuWindowingPillPosition = new PointF(); + private final PointF mHandleMenuMoreActionsPillPosition = new PointF(); + + // Collection of additional windows that comprise the handle menu. + private AdditionalWindow mHandleMenuAppInfoPill; + private AdditionalWindow mHandleMenuWindowingPill; + private AdditionalWindow mHandleMenuMoreActionsPill; + + private Drawable mAppIcon; + private CharSequence mAppName; DesktopModeWindowDecoration( Context context, @@ -95,6 +105,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mHandler = handler; mChoreographer = choreographer; mSyncQueue = syncQueue; + + loadAppInfo(); } @Override @@ -185,7 +197,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mWindowDecorViewHolder = new DesktopModeAppControlsWindowDecorationViewHolder( mResult.mRootView, mOnCaptionTouchListener, - mOnCaptionButtonClickListener + mOnCaptionButtonClickListener, + mAppName, + mAppIcon ); } else { throw new IllegalArgumentException("Unexpected layout resource id"); @@ -225,40 +239,20 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop); } - private void setupHandleMenu() { - final View menu = mHandleMenu.mWindowViewHost.getView(); - final View fullscreen = menu.findViewById(R.id.fullscreen_button); - fullscreen.setOnClickListener(mOnCaptionButtonClickListener); - final View desktop = menu.findViewById(R.id.desktop_button); - desktop.setOnClickListener(mOnCaptionButtonClickListener); - final ViewGroup windowingBtns = menu.findViewById(R.id.windowing_mode_buttons); - windowingBtns.setVisibility(DesktopModeStatus.isProto1Enabled() ? View.GONE : View.VISIBLE); - final View split = menu.findViewById(R.id.split_screen_button); - split.setOnClickListener(mOnCaptionButtonClickListener); - final View close = menu.findViewById(R.id.close_button); - close.setOnClickListener(mOnCaptionButtonClickListener); - final View collapse = menu.findViewById(R.id.collapse_menu_button); - collapse.setOnClickListener(mOnCaptionButtonClickListener); - menu.setOnTouchListener(mOnCaptionTouchListener); - - final ImageView appIcon = menu.findViewById(R.id.application_icon); - final TextView appName = menu.findViewById(R.id.application_name); - loadAppInfo(appName, appIcon); - } - boolean isHandleMenuActive() { - return mHandleMenu != null; + return mHandleMenuAppInfoPill != null; } - private void loadAppInfo(TextView appNameTextView, ImageView appIconImageView) { + private void loadAppInfo() { String packageName = mTaskInfo.realActivity.getPackageName(); PackageManager pm = mContext.getApplicationContext().getPackageManager(); try { - // TODO(b/268363572): Use IconProvider or BaseIconCache to set drawable/name. + IconProvider provider = new IconProvider(mContext); + mAppIcon = provider.getIcon(pm.getActivityInfo(mTaskInfo.baseActivity, + PackageManager.ComponentInfoFlags.of(0))); ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(0)); - appNameTextView.setText(pm.getApplicationLabel(applicationInfo)); - appIconImageView.setImageDrawable(pm.getApplicationIcon(applicationInfo)); + mAppName = pm.getApplicationLabel(applicationInfo); } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Package not found: " + packageName, e); } @@ -280,34 +274,142 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final Resources resources = mDecorWindowContext.getResources(); final int captionWidth = mTaskInfo.getConfiguration() .windowConfiguration.getBounds().width(); - final int menuWidth = loadDimensionPixelSize(resources, mHandleMenuWidthId); - // The windowing controls are disabled in proto1. - final int menuHeight = loadDimensionPixelSize(resources, DesktopModeStatus.isProto1Enabled() - ? mCaptionMenuHeightWithoutWindowingControlsId : mCaptionMenuHeightId); - final int shadowRadius = loadDimensionPixelSize(resources, mHandleMenuShadowRadiusId); - final int cornerRadius = loadDimensionPixelSize(resources, mHandleMenuCornerRadiusId); - - final int x, y; + final int menuWidth = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_width); + final int shadowRadius = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_shadow_radius); + final int cornerRadius = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_corner_radius); + final int marginMenuTop = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_margin_top); + final int marginMenuStart = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_margin_start); + final int marginMenuSpacing = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_pill_spacing_margin); + final int appInfoPillHeight = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_app_info_pill_height); + final int windowingPillHeight = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_windowing_pill_height); + final int moreActionsPillHeight = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_more_actions_pill_height); + + final int menuX, menuY; if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_controls_window_decor) { // Align the handle menu to the left of the caption. - x = mRelayoutParams.mCaptionX - mResult.mDecorContainerOffsetX; - y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; + menuX = mRelayoutParams.mCaptionX - mResult.mDecorContainerOffsetX + marginMenuStart; + menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + marginMenuTop; } else { // Position the handle menu at the center of the caption. - x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2) + menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2) - mResult.mDecorContainerOffsetX; - y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; + menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + marginMenuStart; } - mHandleMenuPosition.set(x, y); - final String namePrefix = "Caption Menu"; - mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y, - menuWidth, menuHeight, shadowRadius, cornerRadius); + + final int appInfoPillY = menuY; + createAppInfoPill(t, menuX, appInfoPillY, menuWidth, appInfoPillHeight, shadowRadius, + cornerRadius); + + // Only show windowing buttons in proto2. Proto1 uses a system-level mode only. + final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled(); + final int windowingPillY = appInfoPillY + appInfoPillHeight + marginMenuSpacing; + if (shouldShowWindowingPill) { + createWindowingPill(t, menuX, windowingPillY, menuWidth, windowingPillHeight, + shadowRadius, + cornerRadius); + } + + final int moreActionsPillY; + if (shouldShowWindowingPill) { + // Take into account the windowing pill height and margins. + moreActionsPillY = windowingPillY + windowingPillHeight + marginMenuSpacing; + } else { + // Just start after the end of the app info pill + margins. + moreActionsPillY = appInfoPillY + appInfoPillHeight + marginMenuSpacing; + } + createMoreActionsPill(t, menuX, moreActionsPillY, menuWidth, moreActionsPillHeight, + shadowRadius, cornerRadius); + mSyncQueue.runInSync(transaction -> { transaction.merge(t); t.close(); }); - setupHandleMenu(); + setupHandleMenu(shouldShowWindowingPill); + } + + private void createAppInfoPill(SurfaceControl.Transaction t, int x, int y, int width, + int height, int shadowRadius, int cornerRadius) { + mHandleMenuAppInfoPillPosition.set(x, y); + mHandleMenuAppInfoPill = addWindow( + R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, + "Menu's app info pill", + t, x, y, width, height, shadowRadius, cornerRadius); + } + + private void createWindowingPill(SurfaceControl.Transaction t, int x, int y, int width, + int height, int shadowRadius, int cornerRadius) { + mHandleMenuWindowingPillPosition.set(x, y); + mHandleMenuWindowingPill = addWindow( + R.layout.desktop_mode_window_decor_handle_menu_windowing_pill, + "Menu's windowing pill", + t, x, y, width, height, shadowRadius, cornerRadius); + } + + private void createMoreActionsPill(SurfaceControl.Transaction t, int x, int y, int width, + int height, int shadowRadius, int cornerRadius) { + mHandleMenuMoreActionsPillPosition.set(x, y); + mHandleMenuMoreActionsPill = addWindow( + R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill, + "Menu's more actions pill", + t, x, y, width, height, shadowRadius, cornerRadius); + } + + private void setupHandleMenu(boolean windowingPillShown) { + // App Info pill setup. + final View appInfoPillView = mHandleMenuAppInfoPill.mWindowViewHost.getView(); + final ImageButton collapseBtn = appInfoPillView.findViewById(R.id.collapse_menu_button); + final ImageView appIcon = appInfoPillView.findViewById(R.id.application_icon); + final TextView appName = appInfoPillView.findViewById(R.id.application_name); + collapseBtn.setOnClickListener(mOnCaptionButtonClickListener); + appInfoPillView.setOnTouchListener(mOnCaptionTouchListener); + appIcon.setImageDrawable(mAppIcon); + appName.setText(mAppName); + + // Windowing pill setup. + if (windowingPillShown) { + final View windowingPillView = mHandleMenuWindowingPill.mWindowViewHost.getView(); + final ImageButton fullscreenBtn = windowingPillView.findViewById( + R.id.fullscreen_button); + final ImageButton splitscreenBtn = windowingPillView.findViewById( + R.id.split_screen_button); + final ImageButton floatingBtn = windowingPillView.findViewById(R.id.floating_button); + final ImageButton desktopBtn = windowingPillView.findViewById(R.id.desktop_button); + fullscreenBtn.setOnClickListener(mOnCaptionButtonClickListener); + splitscreenBtn.setOnClickListener(mOnCaptionButtonClickListener); + floatingBtn.setOnClickListener(mOnCaptionButtonClickListener); + desktopBtn.setOnClickListener(mOnCaptionButtonClickListener); + // The button corresponding to the windowing mode that the task is currently in uses a + // different color than the others. + final ColorStateList activeColorStateList = ColorStateList.valueOf( + mContext.getColor(R.color.desktop_mode_caption_menu_buttons_color_active)); + final ColorStateList inActiveColorStateList = ColorStateList.valueOf( + mContext.getColor(R.color.desktop_mode_caption_menu_buttons_color_inactive)); + fullscreenBtn.setImageTintList( + mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + ? activeColorStateList : inActiveColorStateList); + splitscreenBtn.setImageTintList( + mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW + ? activeColorStateList : inActiveColorStateList); + floatingBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_PINNED + ? activeColorStateList : inActiveColorStateList); + desktopBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM + ? activeColorStateList : inActiveColorStateList); + } + + // More Actions pill setup. + final View moreActionsPillView = mHandleMenuMoreActionsPill.mWindowViewHost.getView(); + final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button); + closeBtn.setOnClickListener(mOnCaptionButtonClickListener); } /** @@ -315,8 +417,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ void closeHandleMenu() { if (!isHandleMenuActive()) return; - mHandleMenu.releaseView(); - mHandleMenu = null; + mHandleMenuAppInfoPill.releaseView(); + mHandleMenuAppInfoPill = null; + if (mHandleMenuWindowingPill != null) { + mHandleMenuWindowingPill.releaseView(); + mHandleMenuWindowingPill = null; + } + mHandleMenuMoreActionsPill.releaseView(); + mHandleMenuMoreActionsPill = null; } @Override @@ -335,12 +443,29 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // When this is called before the layout is fully inflated, width will be 0. // Menu is not visible in this scenario, so skip the check if that is the case. - if (mHandleMenu.mWindowViewHost.getView().getWidth() == 0) return; + if (mHandleMenuAppInfoPill.mWindowViewHost.getView().getWidth() == 0) return; PointF inputPoint = offsetCaptionLocation(ev); - if (!pointInView(mHandleMenu.mWindowViewHost.getView(), - inputPoint.x - mHandleMenuPosition.x - mResult.mDecorContainerOffsetX, - inputPoint.y - mHandleMenuPosition.y - mResult.mDecorContainerOffsetY)) { + final boolean pointInAppInfoPill = pointInView( + mHandleMenuAppInfoPill.mWindowViewHost.getView(), + inputPoint.x - mHandleMenuAppInfoPillPosition.x - mResult.mDecorContainerOffsetX, + inputPoint.y - mHandleMenuAppInfoPillPosition.y + - mResult.mDecorContainerOffsetY); + boolean pointInWindowingPill = false; + if (mHandleMenuWindowingPill != null) { + pointInWindowingPill = pointInView(mHandleMenuWindowingPill.mWindowViewHost.getView(), + inputPoint.x - mHandleMenuWindowingPillPosition.x + - mResult.mDecorContainerOffsetX, + inputPoint.y - mHandleMenuWindowingPillPosition.y + - mResult.mDecorContainerOffsetY); + } + final boolean pointInMoreActionsPill = pointInView( + mHandleMenuMoreActionsPill.mWindowViewHost.getView(), + inputPoint.x - mHandleMenuMoreActionsPillPosition.x + - mResult.mDecorContainerOffsetX, + inputPoint.y - mHandleMenuMoreActionsPillPosition.y + - mResult.mDecorContainerOffsetY); + if (!pointInAppInfoPill && !pointInWindowingPill && !pointInMoreActionsPill) { closeHandleMenu(); } } @@ -397,14 +522,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); clickIfPointInView(new PointF(ev.getX(), ev.getY()), handle); } else { - final View menu = mHandleMenu.mWindowViewHost.getView(); - final int captionWidth = mTaskInfo.getConfiguration().windowConfiguration - .getBounds().width(); - final int menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - - (menu.getWidth() / 2); - final PointF inputPoint = new PointF(ev.getX() - menuX, ev.getY()); - final View collapse = menu.findViewById(R.id.collapse_menu_button); - if (clickIfPointInView(inputPoint, collapse)) return; + final View appInfoPill = mHandleMenuAppInfoPill.mWindowViewHost.getView(); + final ImageButton collapse = appInfoPill.findViewById(R.id.collapse_menu_button); + // Translate the input point from display coordinates to the same space as the collapse + // button, meaning its parent (app info pill view). + final PointF inputPoint = new PointF(ev.getX() - mHandleMenuAppInfoPillPosition.x, + ev.getY() - mHandleMenuAppInfoPillPosition.y); + clickIfPointInView(inputPoint, collapse); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt index 95b5051cb81d..78cfcbd27ed6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt @@ -1,10 +1,9 @@ package com.android.wm.shell.windowdecor.viewholder import android.app.ActivityManager.RunningTaskInfo -import android.content.pm.PackageManager import android.content.res.ColorStateList +import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable -import android.util.Log import android.view.View import android.widget.ImageButton import android.widget.ImageView @@ -19,7 +18,9 @@ import com.android.wm.shell.R internal class DesktopModeAppControlsWindowDecorationViewHolder( rootView: View, onCaptionTouchListener: View.OnTouchListener, - onCaptionButtonClickListener: View.OnClickListener + onCaptionButtonClickListener: View.OnClickListener, + appName: CharSequence, + appIcon: Drawable ) : DesktopModeWindowDecorationViewHolder(rootView) { private val captionView: View = rootView.findViewById(R.id.desktop_mode_caption) @@ -35,10 +36,11 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( captionHandle.setOnTouchListener(onCaptionTouchListener) openMenuButton.setOnClickListener(onCaptionButtonClickListener) closeWindowButton.setOnClickListener(onCaptionButtonClickListener) + appNameTextView.text = appName + appIconImageView.setImageDrawable(appIcon) } override fun bindData(taskInfo: RunningTaskInfo) { - bindAppInfo(taskInfo) val captionDrawable = captionView.background as GradientDrawable captionDrawable.setColor(taskInfo.taskDescription.statusBarColor) @@ -50,20 +52,6 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( appNameTextView.setTextColor(getCaptionAppNameTextColor(taskInfo)) } - private fun bindAppInfo(taskInfo: RunningTaskInfo) { - val packageName: String = taskInfo.realActivity.packageName - val pm: PackageManager = context.applicationContext.packageManager - try { - // TODO(b/268363572): Use IconProvider or BaseIconCache to set drawable/name. - val applicationInfo = pm.getApplicationInfo(packageName, - PackageManager.ApplicationInfoFlags.of(0)) - appNameTextView.text = pm.getApplicationLabel(applicationInfo) - appIconImageView.setImageDrawable(pm.getApplicationIcon(applicationInfo)) - } catch (e: PackageManager.NameNotFoundException) { - Log.w(TAG, "Package not found: $packageName", e) - } - } - private fun getCaptionAppNameTextColor(taskInfo: RunningTaskInfo): Int { return if (shouldUseLightCaptionColors(taskInfo)) { context.getColor(R.color.desktop_mode_caption_app_name_light) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt index ed93045ec462..91846fafd1db 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt @@ -217,28 +217,37 @@ fun FlickerTest.splitAppLayerBoundsChanges( ) { assertLayers { if (landscapePosLeft) { - this.splitAppLayerBoundsSnapToDivider( + splitAppLayerBoundsSnapToDivider( + component, + landscapePosLeft, + portraitPosTop, + scenario.endRotation + ) + .then() + .isInvisible(component) + .then() + .splitAppLayerBoundsSnapToDivider( component, landscapePosLeft, portraitPosTop, scenario.endRotation ) } else { - this.splitAppLayerBoundsSnapToDivider( - component, - landscapePosLeft, - portraitPosTop, - scenario.endRotation - ) - .then() - .isInvisible(component) - .then() - .splitAppLayerBoundsSnapToDivider( - component, - landscapePosLeft, - portraitPosTop, - scenario.endRotation - ) + splitAppLayerBoundsSnapToDivider( + component, + landscapePosLeft, + portraitPosTop, + scenario.endRotation + ) + .then() + .isInvisible(component) + .then() + .splitAppLayerBoundsSnapToDivider( + component, + landscapePosLeft, + portraitPosTop, + scenario.endRotation + ) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt new file mode 100644 index 000000000000..083cfd294f96 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.flicker.pip + +import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.RequiresDevice +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory +import android.tools.device.flicker.legacy.FlickerBuilder +import android.tools.device.flicker.legacy.FlickerTest +import android.tools.device.flicker.legacy.FlickerTestFactory +import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import com.android.server.wm.flicker.testapp.ActivityOptions +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test the dragging of a PIP window. + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class PipDragTest(flicker: FlickerTest) : PipTransition(flicker) { + private var isDraggedLeft: Boolean = true + override val transition: FlickerBuilder.() -> Unit + get() = { + val stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true") + + setup { + tapl.setEnableRotation(true) + // Launch the PIP activity and wait for it to enter PiP mode + RemoveAllTasksButHomeRule.removeAllTasksButHome() + pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras) + + // determine the direction of dragging to test for + isDraggedLeft = pipApp.isCloserToRightEdge(wmHelper) + } + teardown { + // release the primary pointer after dragging without release + pipApp.releasePipAfterDragging() + + pipApp.exit(wmHelper) + tapl.setEnableRotation(false) + } + transitions { + pipApp.dragPipWindowAwayFromEdgeWithoutRelease(wmHelper, 50) + } + } + + @Postsubmit + @Test + fun pipLayerMovesAwayFromEdge() { + flicker.assertLayers { + val pipLayerList = layers { pipApp.layerMatchesAnyOf(it) && it.isVisible } + pipLayerList.zipWithNext { previous, current -> + if (isDraggedLeft) { + previous.visibleRegion.isToTheRight(current.visibleRegion.region) + } else { + current.visibleRegion.isToTheRight(previous.visibleRegion.region) + } + } + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and + * navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTest> { + return FlickerTestFactory.nonRotationTests() + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt index 7db5ecc484ad..17f174b2195f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.splitscreen -import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.IwTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.isShellTransitionsEnabled @@ -86,16 +85,14 @@ class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) { @Presubmit @Test - fun primaryAppLayerKeepVisible() { - Assume.assumeFalse(isShellTransitionsEnabled) - flicker.layerKeepVisible(primaryApp) - } - - @FlakyTest(bugId = 263213649) - @Test - fun primaryAppLayerKeepVisible_ShellTransit() { - Assume.assumeTrue(isShellTransitionsEnabled) - flicker.layerKeepVisible(primaryApp) + fun primaryAppLayerVisibilityChanges() { + flicker.assertLayers { + this.isVisible(secondaryApp) + .then() + .isInvisible(secondaryApp) + .then() + .isVisible(secondaryApp) + } } @Presubmit @@ -110,7 +107,9 @@ class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) { } } - @Presubmit @Test fun primaryAppWindowKeepVisible() = flicker.appWindowKeepVisible(primaryApp) + @Presubmit + @Test + fun primaryAppWindowKeepVisible() = flicker.appWindowKeepVisible(primaryApp) @Presubmit @Test @@ -127,17 +126,6 @@ class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) { ) } - @FlakyTest(bugId = 263213649) - @Test - fun primaryAppBoundsChanges_ShellTransit() { - Assume.assumeTrue(isShellTransitionsEnabled) - flicker.splitAppLayerBoundsChanges( - primaryApp, - landscapePosLeft = true, - portraitPosTop = false - ) - } - @Presubmit @Test fun secondaryAppBoundsChanges() = @@ -148,7 +136,7 @@ class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) { ) /** {@inheritDoc} */ - @FlakyTest(bugId = 263213649) + @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt index 7901f7502e2c..62936e0f5ca8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt @@ -293,7 +293,7 @@ internal object SplitScreenUtils { wmHelper.currentState.layerState.displays.firstOrNull { !it.isVirtual }?.layerStackSpace ?: error("Display not found") val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS) - dividerBar.drag(Point(displayBounds.width * 1 / 3, displayBounds.height * 2 / 3)) + dividerBar.drag(Point(displayBounds.width * 1 / 3, displayBounds.height * 2 / 3), 2000) wmHelper .StateSyncBuilder() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index 169b9bd4dea7..806bffebd4cb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -253,8 +253,6 @@ public class BackAnimationControllerTest extends ShellTestCase { triggerBackGesture(); - verify(mAppCallback, never()).onBackStarted(any()); - verify(mAppCallback, never()).onBackProgressed(backEventCaptor.capture()); verify(mAppCallback, times(1)).onBackInvoked(); verify(mAnimatorCallback, never()).onBackStarted(any()); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java index 2814ef9e26cc..e7d459893ce8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java @@ -18,14 +18,20 @@ package com.android.wm.shell.back; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.app.WindowConfiguration; +import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; import android.os.RemoteException; @@ -69,11 +75,7 @@ public class CustomizeActivityAnimationTest extends ShellTestCase { mBackAnimationBackground, mock(SurfaceControl.Transaction.class), mock(Choreographer.class)); spyOn(mCustomizeActivityAnimation); - spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader); - doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) - .load(any(), eq(false)); - doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) - .load(any(), eq(true)); + spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation); } RemoteAnimationTarget createAnimationTarget(boolean open) { @@ -87,6 +89,12 @@ public class CustomizeActivityAnimationTest extends ShellTestCase { @Test public void receiveFinishAfterInvoke() throws InterruptedException { + spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader); + doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) + .loadAnimation(any(), eq(false)); + doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) + .loadAnimation(any(), eq(true)); + mCustomizeActivityAnimation.prepareNextAnimation( new BackNavigationInfo.CustomAnimationInfo("TestPackage")); final RemoteAnimationTarget close = createAnimationTarget(false); @@ -112,6 +120,12 @@ public class CustomizeActivityAnimationTest extends ShellTestCase { @Test public void receiveFinishAfterCancel() throws InterruptedException { + spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader); + doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) + .loadAnimation(any(), eq(false)); + doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) + .loadAnimation(any(), eq(true)); + mCustomizeActivityAnimation.prepareNextAnimation( new BackNavigationInfo.CustomAnimationInfo("TestPackage")); final RemoteAnimationTarget close = createAnimationTarget(false); @@ -152,4 +166,67 @@ public class CustomizeActivityAnimationTest extends ShellTestCase { verify(mCustomizeActivityAnimation).onGestureCommitted(); finishCalled.await(1, TimeUnit.SECONDS); } + + @Test + public void testLoadCustomAnimation() { + testLoadCustomAnimation(10, 20, 0); + } + + @Test + public void testLoadCustomAnimationNoEnter() { + testLoadCustomAnimation(0, 10, 0); + } + + @Test + public void testLoadWindowAnimations() { + testLoadCustomAnimation(0, 0, 30); + } + + @Test + public void testCustomAnimationHigherThanWindowAnimations() { + testLoadCustomAnimation(10, 20, 30); + } + + private void testLoadCustomAnimation(int enterResId, int exitResId, int windowAnimations) { + final String testPackage = "TestPackage"; + BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder() + .setCustomAnimation(testPackage, enterResId, exitResId, Color.GREEN) + .setWindowAnimations(testPackage, windowAnimations); + final BackNavigationInfo.CustomAnimationInfo info = builder.build() + .getCustomAnimationInfo(); + + doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader + .mTransitionAnimation) + .loadAppTransitionAnimation(eq(testPackage), eq(enterResId)); + doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader + .mTransitionAnimation) + .loadAppTransitionAnimation(eq(testPackage), eq(exitResId)); + doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader + .mTransitionAnimation) + .loadAnimationAttr(eq(testPackage), eq(windowAnimations), anyInt(), anyBoolean()); + doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader + .mTransitionAnimation).loadDefaultAnimationAttr(anyInt(), anyBoolean()); + + CustomizeActivityAnimation.AnimationLoadResult result = + mCustomizeActivityAnimation.mCustomAnimationLoader.loadAll(info); + + if (exitResId != 0) { + if (enterResId == 0) { + verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, + never()).loadAppTransitionAnimation(eq(testPackage), eq(enterResId)); + verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation) + .loadDefaultAnimationAttr(anyInt(), anyBoolean()); + } else { + assertEquals(result.mEnterAnimation, mMockOpenAnimation); + } + assertEquals(result.mBackgroundColor, Color.GREEN); + assertEquals(result.mCloseAnimation, mMockCloseAnimation); + verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, never()) + .loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean()); + } else if (windowAnimations != 0) { + verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, + times(2)).loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean()); + assertEquals(result.mCloseAnimation, mMockCloseAnimation); + } + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java index e8f3f69ca64e..de967bfa288b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java @@ -29,6 +29,8 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.PendingIntent; import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.res.Resources; import android.graphics.drawable.Icon; import android.os.Bundle; import android.service.notification.StatusBarNotification; @@ -162,4 +164,27 @@ public class BubbleTest extends ShellTestCase { verify(mBubbleMetadataFlagListener, never()).onBubbleMetadataFlagChanged(any()); } + + @Test + public void testBubbleIsConversation_hasConversationShortcut() { + Bubble bubble = createBubbleWithShortcut(); + assertThat(bubble.getShortcutInfo()).isNotNull(); + assertThat(bubble.isConversation()).isTrue(); + } + + @Test + public void testBubbleIsConversation_hasNoShortcut() { + Bubble bubble = new Bubble(mBubbleEntry, mBubbleMetadataFlagListener, null, mMainExecutor); + assertThat(bubble.getShortcutInfo()).isNull(); + assertThat(bubble.isConversation()).isFalse(); + } + + private Bubble createBubbleWithShortcut() { + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) + .setId("mockShortcutId") + .build(); + return new Bubble("mockKey", shortcutInfo, 10, Resources.ID_NULL, + "mockTitle", 0 /* taskId */, "mockLocus", true /* isDismissible */, + mMainExecutor, mBubbleMetadataFlagListener); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipMenuControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipMenuControllerTest.java new file mode 100644 index 000000000000..3a08d32bc430 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipMenuControllerTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip.tv; + +import static android.view.KeyEvent.KEYCODE_DPAD_UP; + +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_ALL_ACTIONS_MENU; +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_MOVE_MENU; +import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_NO_MENU; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.os.Handler; +import android.view.SurfaceControl; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.SystemWindows; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class TvPipMenuControllerTest extends ShellTestCase { + private static final int TEST_MOVE_KEYCODE = KEYCODE_DPAD_UP; + + @Mock + private TvPipMenuController.Delegate mMockDelegate; + @Mock + private TvPipBoundsState mMockTvPipBoundsState; + @Mock + private SystemWindows mMockSystemWindows; + @Mock + private SurfaceControl mMockPipLeash; + @Mock + private Handler mMockHandler; + @Mock + private TvPipActionsProvider mMockActionsProvider; + @Mock + private TvPipMenuView mMockTvPipMenuView; + @Mock + private TvPipBackgroundView mMockTvPipBackgroundView; + + private TvPipMenuController mTvPipMenuController; + + @Before + public void setUp() { + assumeTrue(isTelevision()); + + MockitoAnnotations.initMocks(this); + + mTvPipMenuController = new TestTvPipMenuController(); + mTvPipMenuController.setDelegate(mMockDelegate); + mTvPipMenuController.setTvPipActionsProvider(mMockActionsProvider); + mTvPipMenuController.attach(mMockPipLeash); + } + + @Test + public void testMenuNotOpenByDefault() { + assertMenuIsOpen(false); + } + + @Test + public void testSwitch_FromNoMenuMode_ToMoveMode() { + showAndAssertMoveMenu(); + } + + @Test + public void testSwitch_FromNoMenuMode_ToAllActionsMode() { + showAndAssertAllActionsMenu(); + } + + @Test + public void testSwitch_FromMoveMode_ToAllActionsMode() { + showAndAssertMoveMenu(); + showAndAssertAllActionsMenu(); + } + + @Test + public void testSwitch_FromAllActionsMode_ToMoveMode() { + showAndAssertAllActionsMenu(); + showAndAssertMoveMenu(); + } + + @Test + public void testCloseMenu_NoMenuMode() { + mTvPipMenuController.closeMenu(); + assertMenuIsOpen(false); + verify(mMockDelegate, never()).onMenuClosed(); + } + + @Test + public void testCloseMenu_MoveMode() { + showAndAssertMoveMenu(); + + closeMenuAndAssertMenuClosed(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + } + + @Test + public void testCloseMenu_AllActionsMode() { + showAndAssertAllActionsMenu(); + + closeMenuAndAssertMenuClosed(); + } + + @Test + public void testCloseMenu_MoveModeFollowedByAllActionsMode() { + showAndAssertMoveMenu(); + showAndAssertAllActionsMenu(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + + closeMenuAndAssertMenuClosed(); + } + + @Test + public void testCloseMenu_AllActionsModeFollowedByMoveMode() { + showAndAssertAllActionsMenu(); + showAndAssertMoveMenu(); + + closeMenuAndAssertMenuClosed(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + } + + @Test + public void testExitMoveMode_NoMenuMode() { + mTvPipMenuController.onExitMoveMode(); + assertMenuIsOpen(false); + verify(mMockDelegate, never()).onMenuClosed(); + } + + @Test + public void testExitMoveMode_MoveMode() { + showAndAssertMoveMenu(); + + mTvPipMenuController.onExitMoveMode(); + assertMenuClosed(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + } + + @Test + public void testExitMoveMode_AllActionsMode() { + showAndAssertAllActionsMenu(); + + mTvPipMenuController.onExitMoveMode(); + assertMenuIsInAllActionsMode(); + + } + + @Test + public void testExitMoveMode_AllActionsModeFollowedByMoveMode() { + showAndAssertAllActionsMenu(); + showAndAssertMoveMenu(); + + mTvPipMenuController.onExitMoveMode(); + assertMenuIsInAllActionsMode(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + verify(mMockTvPipMenuView).transitionToMenuMode(eq(MODE_ALL_ACTIONS_MENU), eq(false)); + verify(mMockTvPipBackgroundView, times(2)).transitionToMenuMode(eq(MODE_ALL_ACTIONS_MENU)); + } + + @Test + public void testOnBackPress_NoMenuMode() { + mTvPipMenuController.onBackPress(); + assertMenuIsOpen(false); + verify(mMockDelegate, never()).onMenuClosed(); + } + + @Test + public void testOnBackPress_MoveMode() { + showAndAssertMoveMenu(); + + pressBackAndAssertMenuClosed(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + } + + @Test + public void testOnBackPress_AllActionsMode() { + showAndAssertAllActionsMenu(); + + pressBackAndAssertMenuClosed(); + } + + @Test + public void testOnBackPress_MoveModeFollowedByAllActionsMode() { + showAndAssertMoveMenu(); + showAndAssertAllActionsMenu(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + + pressBackAndAssertMenuClosed(); + } + + @Test + public void testOnBackPress_AllActionsModeFollowedByMoveMode() { + showAndAssertAllActionsMenu(); + showAndAssertMoveMenu(); + + mTvPipMenuController.onBackPress(); + assertMenuIsInAllActionsMode(); + verify(mMockDelegate, times(2)).onInMoveModeChanged(); + verify(mMockTvPipMenuView).transitionToMenuMode(eq(MODE_ALL_ACTIONS_MENU), eq(false)); + verify(mMockTvPipBackgroundView, times(2)).transitionToMenuMode(eq(MODE_ALL_ACTIONS_MENU)); + + pressBackAndAssertMenuClosed(); + } + + @Test + public void testOnPipMovement_NoMenuMode() { + assertPipMoveSuccessful(false, mTvPipMenuController.onPipMovement(TEST_MOVE_KEYCODE)); + } + + @Test + public void testOnPipMovement_MoveMode() { + showAndAssertMoveMenu(); + assertPipMoveSuccessful(true, mTvPipMenuController.onPipMovement(TEST_MOVE_KEYCODE)); + verify(mMockDelegate).movePip(eq(TEST_MOVE_KEYCODE)); + } + + @Test + public void testOnPipMovement_AllActionsMode() { + showAndAssertAllActionsMenu(); + assertPipMoveSuccessful(false, mTvPipMenuController.onPipMovement(TEST_MOVE_KEYCODE)); + } + + @Test + public void testOnPipWindowFocusChanged_NoMenuMode() { + mTvPipMenuController.onPipWindowFocusChanged(false); + assertMenuIsOpen(false); + } + + @Test + public void testOnPipWindowFocusChanged_MoveMode() { + showAndAssertMoveMenu(); + mTvPipMenuController.onPipWindowFocusChanged(false); + assertMenuClosed(); + } + + @Test + public void testOnPipWindowFocusChanged_AllActionsMode() { + showAndAssertAllActionsMenu(); + mTvPipMenuController.onPipWindowFocusChanged(false); + assertMenuClosed(); + } + + private void showAndAssertMoveMenu() { + mTvPipMenuController.showMovementMenu(); + assertMenuIsInMoveMode(); + verify(mMockDelegate).onInMoveModeChanged(); + verify(mMockTvPipMenuView).transitionToMenuMode(eq(MODE_MOVE_MENU), eq(false)); + verify(mMockTvPipBackgroundView).transitionToMenuMode(eq(MODE_MOVE_MENU)); + } + + private void showAndAssertAllActionsMenu() { + mTvPipMenuController.showMenu(); + assertMenuIsInAllActionsMode(); + verify(mMockTvPipMenuView).transitionToMenuMode(eq(MODE_ALL_ACTIONS_MENU), eq(true)); + verify(mMockTvPipBackgroundView).transitionToMenuMode(eq(MODE_ALL_ACTIONS_MENU)); + } + + private void closeMenuAndAssertMenuClosed() { + mTvPipMenuController.closeMenu(); + assertMenuClosed(); + } + + private void pressBackAndAssertMenuClosed() { + mTvPipMenuController.onBackPress(); + assertMenuClosed(); + } + + private void assertMenuClosed() { + assertMenuIsOpen(false); + verify(mMockDelegate).onMenuClosed(); + verify(mMockTvPipMenuView).transitionToMenuMode(eq(MODE_NO_MENU), eq(false)); + verify(mMockTvPipBackgroundView).transitionToMenuMode(eq(MODE_NO_MENU)); + } + + private void assertMenuIsOpen(boolean open) { + assertTrue("The TV PiP menu should " + (open ? "" : "not ") + "be open, but it" + + " is in mode " + mTvPipMenuController.getMenuModeString(), + mTvPipMenuController.isMenuOpen() == open); + } + + private void assertMenuIsInMoveMode() { + assertTrue("Expected MODE_MOVE_MENU, but got " + mTvPipMenuController.getMenuModeString(), + mTvPipMenuController.isInMoveMode()); + assertMenuIsOpen(true); + } + + private void assertMenuIsInAllActionsMode() { + assertTrue("Expected MODE_ALL_ACTIONS_MENU, but got " + + mTvPipMenuController.getMenuModeString(), + mTvPipMenuController.isInAllActionsMode()); + assertMenuIsOpen(true); + } + + private void assertPipMoveSuccessful(boolean expected, boolean actual) { + assertTrue("Should " + (expected ? "" : "not ") + "move PiP when the menu is in mode " + + mTvPipMenuController.getMenuModeString(), expected == actual); + } + + private class TestTvPipMenuController extends TvPipMenuController { + + TestTvPipMenuController() { + super(mContext, mMockTvPipBoundsState, mMockSystemWindows, mMockHandler); + } + + @Override + TvPipMenuView createTvPipMenuView() { + return mMockTvPipMenuView; + } + + @Override + TvPipBackgroundView createTvPipBackgroundView() { + return mMockTvPipBackgroundView; + } + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index 1a1bebd28aef..784ad9b006b6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -126,12 +126,6 @@ public final class StageTaskListenerTests extends ShellTestCase { verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true)); } - @Test(expected = IllegalArgumentException.class) - public void testUnknownTaskVanished() { - final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); - mStageTaskListener.onTaskVanished(task); - } - @Test public void testTaskVanished() { // With shell transitions, the transition manages status changes, so skip this test. diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java index 62bfd17cefba..b6d7ff3cd5cf 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.taskview; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; @@ -53,6 +53,8 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.HandlerExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue.TransactionRunnable; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index c92d2f36d3a7..dfa3c1010eed 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -583,7 +583,7 @@ public class WindowDecorationTests extends ShellTestCase { int cornerRadius = loadDimensionPixelSize(resources, mCaptionMenuCornerRadiusId); String name = "Test Window"; WindowDecoration.AdditionalWindow additionalWindow = - addWindow(R.layout.desktop_mode_decor_handle_menu, name, + addWindow(R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, name, mMockSurfaceControlAddWindowT, x - mRelayoutResult.mDecorContainerOffsetX, y - mRelayoutResult.mDecorContainerOffsetY, diff --git a/libs/dream/lowlight/Android.bp b/libs/dream/lowlight/Android.bp index 5b5b0f07cabd..e4d2e022cd76 100644 --- a/libs/dream/lowlight/Android.bp +++ b/libs/dream/lowlight/Android.bp @@ -25,6 +25,7 @@ filegroup { name: "low_light_dream_lib-sources", srcs: [ "src/**/*.java", + "src/**/*.kt", ], path: "src", } @@ -37,10 +38,15 @@ android_library { resource_dirs: [ "res", ], + libs: [ + "kotlin-annotations", + ], static_libs: [ "androidx.arch.core_core-runtime", "dagger2", "jsr330", + "kotlinx-coroutines-android", + "kotlinx-coroutines-core", ], manifest: "AndroidManifest.xml", plugins: ["dagger2-compiler"], diff --git a/libs/dream/lowlight/res/values/config.xml b/libs/dream/lowlight/res/values/config.xml index 70fe0738a6f4..78fefbf41141 100644 --- a/libs/dream/lowlight/res/values/config.xml +++ b/libs/dream/lowlight/res/values/config.xml @@ -17,4 +17,7 @@ <resources> <!-- The dream component used when the device is low light environment. --> <string translatable="false" name="config_lowLightDreamComponent"/> + <!-- The max number of milliseconds to wait for the low light transition before setting + the system dream component --> + <integer name="config_lowLightTransitionTimeoutMs">2000</integer> </resources> diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java deleted file mode 100644 index 3125f088c72b..000000000000 --- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dream.lowlight; - -import static com.android.dream.lowlight.dagger.LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT; - -import android.annotation.IntDef; -import android.annotation.RequiresPermission; -import android.app.DreamManager; -import android.content.ComponentName; -import android.util.Log; - -import androidx.annotation.Nullable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Inject; -import javax.inject.Named; - -/** - * Maintains the ambient light mode of the environment the device is in, and sets a low light dream - * component, if present, as the system dream when the ambient light mode is low light. - * - * @hide - */ -public final class LowLightDreamManager { - private static final String TAG = "LowLightDreamManager"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - /** - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "AMBIENT_LIGHT_MODE_" }, value = { - AMBIENT_LIGHT_MODE_UNKNOWN, - AMBIENT_LIGHT_MODE_REGULAR, - AMBIENT_LIGHT_MODE_LOW_LIGHT - }) - public @interface AmbientLightMode {} - - /** - * Constant for ambient light mode being unknown. - * @hide - */ - public static final int AMBIENT_LIGHT_MODE_UNKNOWN = 0; - - /** - * Constant for ambient light mode being regular / bright. - * @hide - */ - public static final int AMBIENT_LIGHT_MODE_REGULAR = 1; - - /** - * Constant for ambient light mode being low light / dim. - * @hide - */ - public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2; - - private final DreamManager mDreamManager; - private final LowLightTransitionCoordinator mLowLightTransitionCoordinator; - - @Nullable - private final ComponentName mLowLightDreamComponent; - - private int mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN; - - @Inject - public LowLightDreamManager( - DreamManager dreamManager, - LowLightTransitionCoordinator lowLightTransitionCoordinator, - @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) { - mDreamManager = dreamManager; - mLowLightTransitionCoordinator = lowLightTransitionCoordinator; - mLowLightDreamComponent = lowLightDreamComponent; - } - - /** - * Sets the current ambient light mode. - * @hide - */ - @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) - public void setAmbientLightMode(@AmbientLightMode int ambientLightMode) { - if (mLowLightDreamComponent == null) { - if (DEBUG) { - Log.d(TAG, "ignore ambient light mode change because low light dream component " - + "is empty"); - } - return; - } - - if (mAmbientLightMode == ambientLightMode) { - return; - } - - if (DEBUG) { - Log.d(TAG, "ambient light mode changed from " + mAmbientLightMode + " to " - + ambientLightMode); - } - - mAmbientLightMode = ambientLightMode; - - boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT; - mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight, - () -> mDreamManager.setSystemDreamComponent( - shouldEnterLowLight ? mLowLightDreamComponent : null)); - } -} diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt new file mode 100644 index 000000000000..96bfb78eff0d --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.dream.lowlight + +import android.Manifest +import android.annotation.IntDef +import android.annotation.RequiresPermission +import android.app.DreamManager +import android.content.ComponentName +import android.util.Log +import com.android.dream.lowlight.dagger.LowLightDreamModule +import com.android.dream.lowlight.dagger.qualifiers.Application +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Named +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +/** + * Maintains the ambient light mode of the environment the device is in, and sets a low light dream + * component, if present, as the system dream when the ambient light mode is low light. + * + * @hide + */ +class LowLightDreamManager @Inject constructor( + @Application private val coroutineScope: CoroutineScope, + private val dreamManager: DreamManager, + private val lowLightTransitionCoordinator: LowLightTransitionCoordinator, + @param:Named(LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT) + private val lowLightDreamComponent: ComponentName?, + @param:Named(LowLightDreamModule.LOW_LIGHT_TRANSITION_TIMEOUT_MS) + private val lowLightTransitionTimeoutMs: Long +) { + /** + * @hide + */ + @Retention(AnnotationRetention.SOURCE) + @IntDef( + prefix = ["AMBIENT_LIGHT_MODE_"], + value = [ + AMBIENT_LIGHT_MODE_UNKNOWN, + AMBIENT_LIGHT_MODE_REGULAR, + AMBIENT_LIGHT_MODE_LOW_LIGHT + ] + ) + annotation class AmbientLightMode + + private var mTransitionJob: Job? = null + private var mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN + private val mLowLightTransitionTimeout = + lowLightTransitionTimeoutMs.toDuration(DurationUnit.MILLISECONDS) + + /** + * Sets the current ambient light mode. + * + * @hide + */ + @RequiresPermission(Manifest.permission.WRITE_DREAM_STATE) + fun setAmbientLightMode(@AmbientLightMode ambientLightMode: Int) { + if (lowLightDreamComponent == null) { + if (DEBUG) { + Log.d( + TAG, + "ignore ambient light mode change because low light dream component is empty" + ) + } + return + } + if (mAmbientLightMode == ambientLightMode) { + return + } + if (DEBUG) { + Log.d( + TAG, "ambient light mode changed from $mAmbientLightMode to $ambientLightMode" + ) + } + mAmbientLightMode = ambientLightMode + val shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT + + // Cancel any previous transitions + mTransitionJob?.cancel() + mTransitionJob = coroutineScope.launch { + try { + lowLightTransitionCoordinator.waitForLowLightTransitionAnimation( + timeout = mLowLightTransitionTimeout, + entering = shouldEnterLowLight + ) + } catch (ex: TimeoutCancellationException) { + Log.e(TAG, "timed out while waiting for low light animation", ex) + } + dreamManager.setSystemDreamComponent( + if (shouldEnterLowLight) lowLightDreamComponent else null + ) + } + } + + companion object { + private const val TAG = "LowLightDreamManager" + private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) + + /** + * Constant for ambient light mode being unknown. + * + * @hide + */ + const val AMBIENT_LIGHT_MODE_UNKNOWN = 0 + + /** + * Constant for ambient light mode being regular / bright. + * + * @hide + */ + const val AMBIENT_LIGHT_MODE_REGULAR = 1 + + /** + * Constant for ambient light mode being low light / dim. + * + * @hide + */ + const val AMBIENT_LIGHT_MODE_LOW_LIGHT = 2 + } +} diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java deleted file mode 100644 index 874a2d5af75e..000000000000 --- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dream.lowlight; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.annotation.Nullable; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Helper class that allows listening and running animations before entering or exiting low light. - */ -@Singleton -public class LowLightTransitionCoordinator { - /** - * Listener that is notified before low light entry. - */ - public interface LowLightEnterListener { - /** - * Callback that is notified before the device enters low light. - * - * @return an optional animator that will be waited upon before entering low light. - */ - Animator onBeforeEnterLowLight(); - } - - /** - * Listener that is notified before low light exit. - */ - public interface LowLightExitListener { - /** - * Callback that is notified before the device exits low light. - * - * @return an optional animator that will be waited upon before exiting low light. - */ - Animator onBeforeExitLowLight(); - } - - private LowLightEnterListener mLowLightEnterListener; - private LowLightExitListener mLowLightExitListener; - - @Inject - public LowLightTransitionCoordinator() { - } - - /** - * Sets the listener for the low light enter event. - * - * Only one listener can be set at a time. This method will overwrite any previously set - * listener. Null can be used to unset the listener. - */ - public void setLowLightEnterListener(@Nullable LowLightEnterListener lowLightEnterListener) { - mLowLightEnterListener = lowLightEnterListener; - } - - /** - * Sets the listener for the low light exit event. - * - * Only one listener can be set at a time. This method will overwrite any previously set - * listener. Null can be used to unset the listener. - */ - public void setLowLightExitListener(@Nullable LowLightExitListener lowLightExitListener) { - mLowLightExitListener = lowLightExitListener; - } - - /** - * Notifies listeners that the device is about to enter or exit low light. - * - * @param entering true if listeners should be notified before entering low light, false if this - * is notifying before exiting. - * @param callback callback that will be run after listeners complete. - */ - void notifyBeforeLowLightTransition(boolean entering, Runnable callback) { - Animator animator = null; - - if (entering && mLowLightEnterListener != null) { - animator = mLowLightEnterListener.onBeforeEnterLowLight(); - } else if (!entering && mLowLightExitListener != null) { - animator = mLowLightExitListener.onBeforeExitLowLight(); - } - - // If the listener returned an animator to indicate it was running an animation, run the - // callback after the animation completes, otherwise call the callback directly. - if (animator != null) { - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - callback.run(); - } - }); - } else { - callback.run(); - } - } -} diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt new file mode 100644 index 000000000000..26efb55fa560 --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.dream.lowlight + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import com.android.dream.lowlight.util.suspendCoroutineWithTimeout +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.coroutines.resume +import kotlin.time.Duration + +/** + * Helper class that allows listening and running animations before entering or exiting low light. + */ +@Singleton +class LowLightTransitionCoordinator @Inject constructor() { + /** + * Listener that is notified before low light entry. + */ + interface LowLightEnterListener { + /** + * Callback that is notified before the device enters low light. + * + * @return an optional animator that will be waited upon before entering low light. + */ + fun onBeforeEnterLowLight(): Animator? + } + + /** + * Listener that is notified before low light exit. + */ + interface LowLightExitListener { + /** + * Callback that is notified before the device exits low light. + * + * @return an optional animator that will be waited upon before exiting low light. + */ + fun onBeforeExitLowLight(): Animator? + } + + private var mLowLightEnterListener: LowLightEnterListener? = null + private var mLowLightExitListener: LowLightExitListener? = null + + /** + * Sets the listener for the low light enter event. + * + * Only one listener can be set at a time. This method will overwrite any previously set + * listener. Null can be used to unset the listener. + */ + fun setLowLightEnterListener(lowLightEnterListener: LowLightEnterListener?) { + mLowLightEnterListener = lowLightEnterListener + } + + /** + * Sets the listener for the low light exit event. + * + * Only one listener can be set at a time. This method will overwrite any previously set + * listener. Null can be used to unset the listener. + */ + fun setLowLightExitListener(lowLightExitListener: LowLightExitListener?) { + mLowLightExitListener = lowLightExitListener + } + + /** + * Notifies listeners that the device is about to enter or exit low light, and waits for the + * animation to complete. If this function is cancelled, the animation is also cancelled. + * + * @param timeout the maximum duration to wait for the transition animation. If the animation + * does not complete within this time period, a + * @param entering true if listeners should be notified before entering low light, false if this + * is notifying before exiting. + */ + suspend fun waitForLowLightTransitionAnimation(timeout: Duration, entering: Boolean) = + suspendCoroutineWithTimeout(timeout) { continuation -> + var animator: Animator? = null + if (entering && mLowLightEnterListener != null) { + animator = mLowLightEnterListener!!.onBeforeEnterLowLight() + } else if (!entering && mLowLightExitListener != null) { + animator = mLowLightExitListener!!.onBeforeExitLowLight() + } + + if (animator == null) { + continuation.resume(Unit) + return@suspendCoroutineWithTimeout + } + + // If the listener returned an animator to indicate it was running an animation, run the + // callback after the animation completes, otherwise call the callback directly. + val listener = object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animator: Animator) { + continuation.resume(Unit) + } + + override fun onAnimationCancel(animation: Animator) { + continuation.cancel() + } + } + animator.addListener(listener) + continuation.invokeOnCancellation { + animator.removeListener(listener) + animator.cancel() + } + } +} diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java deleted file mode 100644 index c183a04cb2f9..000000000000 --- a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dream.lowlight.dagger; - -import android.app.DreamManager; -import android.content.ComponentName; -import android.content.Context; - -import androidx.annotation.Nullable; - -import com.android.dream.lowlight.R; - -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; - -/** - * Dagger module for low light dream. - * - * @hide - */ -@Module -public interface LowLightDreamModule { - String LOW_LIGHT_DREAM_COMPONENT = "low_light_dream_component"; - - /** - * Provides dream manager. - */ - @Provides - static DreamManager providesDreamManager(Context context) { - return context.getSystemService(DreamManager.class); - } - - /** - * Provides the component name of the low light dream, or null if not configured. - */ - @Provides - @Named(LOW_LIGHT_DREAM_COMPONENT) - @Nullable - static ComponentName providesLowLightDreamComponent(Context context) { - final String lowLightDreamComponent = context.getResources().getString( - R.string.config_lowLightDreamComponent); - return lowLightDreamComponent.isEmpty() ? null - : ComponentName.unflattenFromString(lowLightDreamComponent); - } -} diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.kt new file mode 100644 index 000000000000..dd274bd9d509 --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.dream.lowlight.dagger + +import android.app.DreamManager +import android.content.ComponentName +import android.content.Context +import com.android.dream.lowlight.R +import com.android.dream.lowlight.dagger.qualifiers.Application +import com.android.dream.lowlight.dagger.qualifiers.Main +import dagger.Module +import dagger.Provides +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import javax.inject.Named + +/** + * Dagger module for low light dream. + * + * @hide + */ +@Module +object LowLightDreamModule { + /** + * Provides dream manager. + */ + @Provides + fun providesDreamManager(context: Context): DreamManager { + return requireNotNull(context.getSystemService(DreamManager::class.java)) + } + + /** + * Provides the component name of the low light dream, or null if not configured. + */ + @Provides + @Named(LOW_LIGHT_DREAM_COMPONENT) + fun providesLowLightDreamComponent(context: Context): ComponentName? { + val lowLightDreamComponent = context.resources.getString( + R.string.config_lowLightDreamComponent + ) + return if (lowLightDreamComponent.isEmpty()) { + null + } else { + ComponentName.unflattenFromString(lowLightDreamComponent) + } + } + + @Provides + @Named(LOW_LIGHT_TRANSITION_TIMEOUT_MS) + fun providesLowLightTransitionTimeout(context: Context): Long { + return context.resources.getInteger(R.integer.config_lowLightTransitionTimeoutMs).toLong() + } + + @Provides + @Main + fun providesMainDispatcher(): CoroutineDispatcher { + return Dispatchers.Main.immediate + } + + @Provides + @Application + fun providesApplicationScope(@Main dispatcher: CoroutineDispatcher): CoroutineScope { + return CoroutineScope(dispatcher) + } + + const val LOW_LIGHT_DREAM_COMPONENT = "low_light_dream_component" + const val LOW_LIGHT_TRANSITION_TIMEOUT_MS = "low_light_transition_timeout" +} diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/qualifiers/Application.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/qualifiers/Application.kt new file mode 100644 index 000000000000..541fe4017e6e --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/qualifiers/Application.kt @@ -0,0 +1,9 @@ +package com.android.dream.lowlight.dagger.qualifiers + +import android.content.Context +import javax.inject.Qualifier + +/** + * Used to qualify a context as [Context.getApplicationContext] + */ +@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Application diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/qualifiers/Main.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/qualifiers/Main.kt new file mode 100644 index 000000000000..ccd0710bdc60 --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/qualifiers/Main.kt @@ -0,0 +1,8 @@ +package com.android.dream.lowlight.dagger.qualifiers + +import javax.inject.Qualifier + +/** + * Used to qualify code running on the main thread. + */ +@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Main diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/util/KotlinUtils.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/util/KotlinUtils.kt new file mode 100644 index 000000000000..ff675ccfaffb --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/util/KotlinUtils.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dream.lowlight.util + +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withTimeout +import kotlin.time.Duration + +suspend inline fun <T> suspendCoroutineWithTimeout( + timeout: Duration, + crossinline block: (CancellableContinuation<T>) -> Unit +) = withTimeout(timeout) { + suspendCancellableCoroutine(block = block) +} diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp index bd6f05eabac5..2d79090cd7d4 100644 --- a/libs/dream/lowlight/tests/Android.bp +++ b/libs/dream/lowlight/tests/Android.bp @@ -20,6 +20,7 @@ android_test { name: "LowLightDreamTests", srcs: [ "**/*.java", + "**/*.kt", ], static_libs: [ "LowLightDreamLib", @@ -28,6 +29,7 @@ android_test { "androidx.test.ext.junit", "frameworks-base-testutils", "junit", + "kotlinx_coroutines_test", "mockito-target-extended-minus-junit4", "platform-test-annotations", "testables", diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java deleted file mode 100644 index 4b95d8c84bac..000000000000 --- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dream.lowlight; - -import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT; -import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR; -import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN; - -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.doAnswer; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import android.app.DreamManager; -import android.content.ComponentName; -import android.testing.AndroidTestingRunner; - -import androidx.test.filters.SmallTest; - -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) -public class LowLightDreamManagerTest { - @Mock - private DreamManager mDreamManager; - - @Mock - private LowLightTransitionCoordinator mTransitionCoordinator; - - @Mock - private ComponentName mDreamComponent; - - LowLightDreamManager mLowLightDreamManager; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - // Automatically run any provided Runnable to mTransitionCoordinator to simplify testing. - doAnswer(invocation -> { - ((Runnable) invocation.getArgument(1)).run(); - return null; - }).when(mTransitionCoordinator).notifyBeforeLowLightTransition(anyBoolean(), - any(Runnable.class)); - - mLowLightDreamManager = new LowLightDreamManager(mDreamManager, mTransitionCoordinator, - mDreamComponent); - } - - @Test - public void setAmbientLightMode_lowLight_setSystemDream() { - mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); - - verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(true), any()); - verify(mDreamManager).setSystemDreamComponent(mDreamComponent); - } - - @Test - public void setAmbientLightMode_regularLight_clearSystemDream() { - mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR); - - verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(false), any()); - verify(mDreamManager).setSystemDreamComponent(null); - } - - @Test - public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() { - // Set to low light first. - mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); - clearInvocations(mDreamManager); - - // Return to default unknown mode. - mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN); - - verify(mDreamManager).setSystemDreamComponent(null); - } - - @Test - public void setAmbientLightMode_dreamComponentNotSet_doNothing() { - final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, - mTransitionCoordinator, null /*dream component*/); - - lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); - - verify(mDreamManager, never()).setSystemDreamComponent(any()); - } -} diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt new file mode 100644 index 000000000000..2a886bc31788 --- /dev/null +++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.dream.lowlight + +import android.animation.Animator +import android.app.DreamManager +import android.content.ComponentName +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import src.com.android.dream.lowlight.utils.any +import src.com.android.dream.lowlight.utils.withArgCaptor + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidTestingRunner::class) +class LowLightDreamManagerTest { + @Mock + private lateinit var mDreamManager: DreamManager + @Mock + private lateinit var mEnterAnimator: Animator + @Mock + private lateinit var mExitAnimator: Animator + + private lateinit var mTransitionCoordinator: LowLightTransitionCoordinator + private lateinit var mLowLightDreamManager: LowLightDreamManager + private lateinit var testScope: TestScope + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testScope = TestScope(StandardTestDispatcher()) + + mTransitionCoordinator = LowLightTransitionCoordinator() + mTransitionCoordinator.setLowLightEnterListener( + object : LowLightTransitionCoordinator.LowLightEnterListener { + override fun onBeforeEnterLowLight() = mEnterAnimator + }) + mTransitionCoordinator.setLowLightExitListener( + object : LowLightTransitionCoordinator.LowLightExitListener { + override fun onBeforeExitLowLight() = mExitAnimator + }) + + mLowLightDreamManager = LowLightDreamManager( + coroutineScope = testScope, + dreamManager = mDreamManager, + lowLightTransitionCoordinator = mTransitionCoordinator, + lowLightDreamComponent = DREAM_COMPONENT, + lowLightTransitionTimeoutMs = LOW_LIGHT_TIMEOUT_MS + ) + } + + @Test + fun setAmbientLightMode_lowLight_setSystemDream() = testScope.runTest { + mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT) + runCurrent() + verify(mDreamManager, never()).setSystemDreamComponent(DREAM_COMPONENT) + completeEnterAnimations() + runCurrent() + verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT) + } + + @Test + fun setAmbientLightMode_regularLight_clearSystemDream() = testScope.runTest { + mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR) + runCurrent() + verify(mDreamManager, never()).setSystemDreamComponent(null) + completeExitAnimations() + runCurrent() + verify(mDreamManager).setSystemDreamComponent(null) + } + + @Test + fun setAmbientLightMode_defaultUnknownMode_clearSystemDream() = testScope.runTest { + // Set to low light first. + mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT) + runCurrent() + completeEnterAnimations() + runCurrent() + verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT) + clearInvocations(mDreamManager) + + // Return to default unknown mode. + mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN) + runCurrent() + completeExitAnimations() + runCurrent() + verify(mDreamManager).setSystemDreamComponent(null) + } + + @Test + fun setAmbientLightMode_dreamComponentNotSet_doNothing() = testScope.runTest { + val lowLightDreamManager = LowLightDreamManager( + coroutineScope = testScope, + dreamManager = mDreamManager, + lowLightTransitionCoordinator = mTransitionCoordinator, + lowLightDreamComponent = null, + lowLightTransitionTimeoutMs = LOW_LIGHT_TIMEOUT_MS + ) + lowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT) + runCurrent() + verify(mEnterAnimator, never()).addListener(any()) + verify(mDreamManager, never()).setSystemDreamComponent(any()) + } + + @Test + fun setAmbientLightMode_multipleTimesBeforeAnimationEnds_cancelsPrevious() = testScope.runTest { + mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT) + runCurrent() + // If we reset the light mode back to regular before the previous animation finishes, it + // should be ignored. + mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR) + runCurrent() + completeEnterAnimations() + completeExitAnimations() + runCurrent() + verify(mDreamManager, times(1)).setSystemDreamComponent(null) + } + + @Test + fun setAmbientLightMode_animatorNeverFinishes_timesOut() = testScope.runTest { + mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT) + advanceTimeBy(delayTimeMillis = LOW_LIGHT_TIMEOUT_MS + 1) + // Animation never finishes, but we should still set the system dream + verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT) + } + + private fun completeEnterAnimations() { + val listener = withArgCaptor { verify(mEnterAnimator).addListener(capture()) } + listener.onAnimationEnd(mEnterAnimator) + } + + private fun completeExitAnimations() { + val listener = withArgCaptor { verify(mExitAnimator).addListener(capture()) } + listener.onAnimationEnd(mExitAnimator) + } + + companion object { + private val DREAM_COMPONENT = ComponentName("test_package", "test_dream") + private const val LOW_LIGHT_TIMEOUT_MS: Long = 1000 + } +}
\ No newline at end of file diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java deleted file mode 100644 index 81e1e33d6220..000000000000 --- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dream.lowlight; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -import android.animation.Animator; -import android.testing.AndroidTestingRunner; - -import androidx.test.filters.SmallTest; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -public class LowLightTransitionCoordinatorTest { - @Mock - private LowLightTransitionCoordinator.LowLightEnterListener mEnterListener; - - @Mock - private LowLightTransitionCoordinator.LowLightExitListener mExitListener; - - @Mock - private Animator mAnimator; - - @Captor - private ArgumentCaptor<Animator.AnimatorListener> mAnimatorListenerCaptor; - - @Mock - private Runnable mRunnable; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void onEnterCalledOnListeners() { - LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); - - coordinator.setLowLightEnterListener(mEnterListener); - - coordinator.notifyBeforeLowLightTransition(true, mRunnable); - - verify(mEnterListener).onBeforeEnterLowLight(); - verify(mRunnable).run(); - } - - @Test - public void onExitCalledOnListeners() { - LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); - - coordinator.setLowLightExitListener(mExitListener); - - coordinator.notifyBeforeLowLightTransition(false, mRunnable); - - verify(mExitListener).onBeforeExitLowLight(); - verify(mRunnable).run(); - } - - @Test - public void listenerNotCalledAfterRemoval() { - LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); - - coordinator.setLowLightEnterListener(mEnterListener); - coordinator.setLowLightEnterListener(null); - - coordinator.notifyBeforeLowLightTransition(true, mRunnable); - - verifyZeroInteractions(mEnterListener); - verify(mRunnable).run(); - } - - @Test - public void runnableCalledAfterAnimationEnds() { - when(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator); - - LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); - coordinator.setLowLightEnterListener(mEnterListener); - - coordinator.notifyBeforeLowLightTransition(true, mRunnable); - - // Animator listener is added and the runnable is not run yet. - verify(mAnimator).addListener(mAnimatorListenerCaptor.capture()); - verifyZeroInteractions(mRunnable); - - // Runnable is run once the animation ends. - mAnimatorListenerCaptor.getValue().onAnimationEnd(null); - verify(mRunnable).run(); - } -} diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt new file mode 100644 index 000000000000..4c526a6ac69d --- /dev/null +++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.dream.lowlight + +import android.animation.Animator +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.dream.lowlight.LowLightTransitionCoordinator.LowLightEnterListener +import com.android.dream.lowlight.LowLightTransitionCoordinator.LowLightExitListener +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import src.com.android.dream.lowlight.utils.whenever +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +@SmallTest +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidTestingRunner::class) +class LowLightTransitionCoordinatorTest { + @Mock + private lateinit var mEnterListener: LowLightEnterListener + + @Mock + private lateinit var mExitListener: LowLightExitListener + + @Mock + private lateinit var mAnimator: Animator + + @Captor + private lateinit var mAnimatorListenerCaptor: ArgumentCaptor<Animator.AnimatorListener> + + private lateinit var testScope: TestScope + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testScope = TestScope(StandardTestDispatcher()) + } + + @Test + fun onEnterCalledOnListeners() = testScope.runTest { + val coordinator = LowLightTransitionCoordinator() + coordinator.setLowLightEnterListener(mEnterListener) + val job = launch { + coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true) + } + runCurrent() + verify(mEnterListener).onBeforeEnterLowLight() + assertThat(job.isCompleted).isTrue() + } + + @Test + fun onExitCalledOnListeners() = testScope.runTest { + val coordinator = LowLightTransitionCoordinator() + coordinator.setLowLightExitListener(mExitListener) + val job = launch { + coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = false) + } + runCurrent() + verify(mExitListener).onBeforeExitLowLight() + assertThat(job.isCompleted).isTrue() + } + + @Test + fun listenerNotCalledAfterRemoval() = testScope.runTest { + val coordinator = LowLightTransitionCoordinator() + coordinator.setLowLightEnterListener(mEnterListener) + coordinator.setLowLightEnterListener(null) + val job = launch { + coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true) + } + runCurrent() + verify(mEnterListener, never()).onBeforeEnterLowLight() + assertThat(job.isCompleted).isTrue() + } + + @Test + fun waitsForAnimationToEnd() = testScope.runTest { + whenever(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator) + val coordinator = LowLightTransitionCoordinator() + coordinator.setLowLightEnterListener(mEnterListener) + val job = launch { + coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true) + } + runCurrent() + // Animator listener is added and the runnable is not run yet. + verify(mAnimator).addListener(mAnimatorListenerCaptor.capture()) + assertThat(job.isCompleted).isFalse() + + // Runnable is run once the animation ends. + mAnimatorListenerCaptor.value.onAnimationEnd(mAnimator) + runCurrent() + assertThat(job.isCompleted).isTrue() + assertThat(job.isCancelled).isFalse() + } + + @Test + fun waitsForTimeoutIfAnimationNeverEnds() = testScope.runTest { + whenever(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator) + val coordinator = LowLightTransitionCoordinator() + coordinator.setLowLightEnterListener(mEnterListener) + val job = launch { + coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true) + } + runCurrent() + assertThat(job.isCancelled).isFalse() + advanceTimeBy(delayTimeMillis = TIMEOUT.inWholeMilliseconds + 1) + // If animator doesn't complete within the timeout, we should cancel ourselves. + assertThat(job.isCancelled).isTrue() + } + + @Test + fun shouldCancelIfAnimationIsCancelled() = testScope.runTest { + whenever(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator) + val coordinator = LowLightTransitionCoordinator() + coordinator.setLowLightEnterListener(mEnterListener) + val job = launch { + coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true) + } + runCurrent() + // Animator listener is added and the runnable is not run yet. + verify(mAnimator).addListener(mAnimatorListenerCaptor.capture()) + assertThat(job.isCompleted).isFalse() + assertThat(job.isCancelled).isFalse() + + // Runnable is run once the animation ends. + mAnimatorListenerCaptor.value.onAnimationCancel(mAnimator) + runCurrent() + assertThat(job.isCompleted).isTrue() + assertThat(job.isCancelled).isTrue() + } + + @Test + fun shouldCancelAnimatorWhenJobCancelled() = testScope.runTest { + whenever(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator) + val coordinator = LowLightTransitionCoordinator() + coordinator.setLowLightEnterListener(mEnterListener) + val job = launch { + coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true) + } + runCurrent() + // Animator listener is added and the runnable is not run yet. + verify(mAnimator).addListener(mAnimatorListenerCaptor.capture()) + verify(mAnimator, never()).cancel() + assertThat(job.isCompleted).isFalse() + + job.cancel() + // We should have removed the listener and cancelled the animator + verify(mAnimator).removeListener(mAnimatorListenerCaptor.value) + verify(mAnimator).cancel() + } + + companion object { + private val TIMEOUT = 1.toDuration(DurationUnit.SECONDS) + } +} diff --git a/libs/dream/lowlight/tests/src/com/android/dream/lowlight/utils/KotlinMockitoHelpers.kt b/libs/dream/lowlight/tests/src/com/android/dream/lowlight/utils/KotlinMockitoHelpers.kt new file mode 100644 index 000000000000..e5ec26ca4b41 --- /dev/null +++ b/libs/dream/lowlight/tests/src/com/android/dream/lowlight/utils/KotlinMockitoHelpers.kt @@ -0,0 +1,125 @@ +package src.com.android.dream.lowlight.utils + +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatcher +import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.stubbing.OngoingStubbing +import org.mockito.stubbing.Stubber + +/** + * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when + * null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> eq(obj: T): T = Mockito.eq<T>(obj) + +/** + * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when + * null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> any(type: Class<T>): T = Mockito.any<T>(type) +inline fun <reified T> any(): T = any(T::class.java) + +/** + * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when + * null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher) + +/** + * Kotlin type-inferred version of Mockito.nullable() + */ +inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java) + +/** + * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException + * when null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + +/** + * Helper function for creating an argumentCaptor in kotlin. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> = + ArgumentCaptor.forClass(T::class.java) + +/** + * Helper function for creating new mocks, without the need to pass in a [Class] instance. + * + * Generic T is nullable because implicitly bounded by Any?. + * + * @param apply builder function to simplify stub configuration by improving type inference. + */ +inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java) + .apply(apply) + +/** + * Helper function for stubbing methods without the need to use backticks. + * + * @see Mockito.when + */ +fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall) +fun <T> Stubber.whenever(mock: T): T = `when`(mock) + +/** + * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when + * kotlin tests are mocking kotlin objects and the methods take non-null parameters: + * + * java.lang.NullPointerException: capture() must not be null + */ +class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) { + private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz) + fun capture(): T = wrapped.capture() + val value: T + get() = wrapped.value + val allValues: List<T> + get() = wrapped.allValues +} + +/** + * Helper function for creating an argumentCaptor in kotlin. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +inline fun <reified T : Any> kotlinArgumentCaptor(): KotlinArgumentCaptor<T> = + KotlinArgumentCaptor(T::class.java) + +/** + * Helper function for creating and using a single-use ArgumentCaptor in kotlin. + * + * val captor = argumentCaptor<Foo>() + * verify(...).someMethod(captor.capture()) + * val captured = captor.value + * + * becomes: + * + * val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) } + * + * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException. + */ +inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T = + kotlinArgumentCaptor<T>().apply { block() }.value + +/** + * Variant of [withArgCaptor] for capturing multiple arguments. + * + * val captor = argumentCaptor<Foo>() + * verify(...).someMethod(captor.capture()) + * val captured: List<Foo> = captor.allValues + * + * becomes: + * + * val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) } + */ +inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> = + kotlinArgumentCaptor<T>().apply{ block() }.allValues diff --git a/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp index ae22213f4bf4..768dfcd52840 100644 --- a/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp @@ -74,7 +74,7 @@ static long android_graphics_HardwareBufferRenderer_create(JNIEnv* env, jobject, auto* hardwareBuffer = HardwareBufferHelpers::AHardwareBuffer_fromHardwareBuffer(env, buffer); auto* rootRenderNode = reinterpret_cast<RootRenderNode*>(renderNodePtr); ContextFactoryImpl factory(rootRenderNode); - auto* proxy = new RenderProxy(true, rootRenderNode, &factory); + auto* proxy = new RenderProxy(false, rootRenderNode, &factory); proxy->setHardwareBuffer(hardwareBuffer); return (jlong)proxy; } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 6628463bcabf..8ea71f11e2f0 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -499,8 +499,7 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip, } canvas->concat(preTransform); - // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293 - if (!opaque || getSurfaceColorType() == kRGBA_F16_SkColorType) { + if (!opaque) { canvas->clear(SK_ColorTRANSPARENT); } diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index f5a9850b31dd..9be77281eb11 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -831,7 +831,9 @@ public class Location implements Parcelable { * will be present for any location. * * <ul> - * <li> satellites - the number of satellites used to derive a GNSS fix + * <li> satellites - the number of satellites used to derive a GNSS fix. This key was deprecated + * in API 34 because the information can be obtained through more accurate means, such as by + * referencing {@link GnssStatus#usedInFix}. * </ul> */ public @Nullable Bundle getExtras() { diff --git a/media/OWNERS b/media/OWNERS index 5f501372666b..4a6648e91af4 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -1,4 +1,5 @@ # Bug component: 1344 +atneya@google.com elaurent@google.com essick@google.com etalvala@google.com diff --git a/media/aidl/android/media/soundtrigger_middleware/OWNERS b/media/aidl/android/media/soundtrigger_middleware/OWNERS index 01b2cb981bbb..1e41886fe716 100644 --- a/media/aidl/android/media/soundtrigger_middleware/OWNERS +++ b/media/aidl/android/media/soundtrigger_middleware/OWNERS @@ -1,2 +1 @@ -atneya@google.com -elaurent@google.com +include /media/java/android/media/soundtrigger/OWNERS diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 293d3d2861cd..e73cf87ba9f3 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -70,7 +70,7 @@ public class AudioSystem throw new UnsupportedOperationException("Trying to instantiate AudioSystem"); } - /* These values must be kept in sync with system/audio.h */ + /* These values must be kept in sync with system/media/audio/include/system/audio-hal-enums.h */ /* * If these are modified, please also update Settings.System.VOLUME_SETTINGS * and attrs.xml and AudioManager.java. @@ -961,7 +961,8 @@ public class AudioSystem */ // - // audio device definitions: must be kept in sync with values in system/core/audio.h + // audio device definitions: must be kept in sync with values + // in system/media/audio/include/system/audio-hal-enums.h // /** @hide */ public static final int DEVICE_NONE = 0x0; diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 3ba1d1f0eca2..c1ee74a70a15 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -75,11 +75,13 @@ public class AudioPolicy { */ public static final int POLICY_STATUS_REGISTERED = 2; + @GuardedBy("mLock") private int mStatus; + @GuardedBy("mLock") private String mRegistrationId; - private AudioPolicyStatusListener mStatusListener; - private boolean mIsFocusPolicy; - private boolean mIsTestFocusPolicy; + private final AudioPolicyStatusListener mStatusListener; + private final boolean mIsFocusPolicy; + private final boolean mIsTestFocusPolicy; /** * The list of AudioTrack instances created to inject audio into the associated mixes @@ -115,6 +117,7 @@ public class AudioPolicy { private Context mContext; + @GuardedBy("mLock") private AudioPolicyConfig mConfig; private final MediaProjection mProjection; @@ -552,7 +555,6 @@ public class AudioPolicy { /** @hide */ public void reset() { setRegistration(null); - mConfig.reset(); } public void setRegistration(String regId) { @@ -563,6 +565,7 @@ public class AudioPolicy { mStatus = POLICY_STATUS_REGISTERED; } else { mStatus = POLICY_STATUS_UNREGISTERED; + mConfig.reset(); } } sendMsg(MSG_POLICY_STATUS_CHANGE); @@ -940,14 +943,9 @@ public class AudioPolicy { } private void onPolicyStatusChange() { - AudioPolicyStatusListener l; - synchronized (mLock) { - if (mStatusListener == null) { - return; - } - l = mStatusListener; + if (mStatusListener != null) { + mStatusListener.onStatusChange(); } - l.onStatusChange(); } //================================================== diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java index ce9773312a10..7a85d21bf144 100644 --- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java +++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java @@ -42,9 +42,7 @@ public class AudioPolicyConfig implements Parcelable { private String mRegistrationId = null; - /** counter for the mixes that are / have been in the list of AudioMix - * e.g. register 4 mixes (counter is 3), remove 1 (counter is 3), add 1 (counter is 4) - */ + // Corresponds to id of next mix to be registered. private int mMixCounter = 0; protected AudioPolicyConfig(AudioPolicyConfig conf) { @@ -286,7 +284,7 @@ public class AudioPolicyConfig implements Parcelable { if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) == AudioMix.ROUTE_FLAG_LOOP_BACK) { mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":" - + mMixCounter); + + mMixCounter++); } else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) == AudioMix.ROUTE_FLAG_RENDER) { mix.setRegistration(mix.mDeviceAddress); @@ -294,7 +292,6 @@ public class AudioPolicyConfig implements Parcelable { } else { mix.setRegistration(""); } - mMixCounter++; } @GuardedBy("mMixes") diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl index 2bdd5c8bc977..5f7d636fdd1e 100644 --- a/media/java/android/media/projection/IMediaProjection.aidl +++ b/media/java/android/media/projection/IMediaProjection.aidl @@ -23,22 +23,32 @@ import android.os.IBinder; interface IMediaProjection { void start(IMediaProjectionCallback callback); void stop(); + boolean canProjectAudio(); boolean canProjectVideo(); boolean canProjectSecureVideo(); + + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MANAGE_MEDIA_PROJECTION)") int applyVirtualDisplayFlags(int flags); + void registerCallback(IMediaProjectionCallback callback); + void unregisterCallback(IMediaProjectionCallback callback); /** * Returns the {@link android.os.IBinder} identifying the task to record, or {@code null} if * there is none. */ + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MANAGE_MEDIA_PROJECTION)") IBinder getLaunchCookie(); /** * Updates the {@link android.os.IBinder} identifying the task to record, or {@code null} if * there is none. */ + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MANAGE_MEDIA_PROJECTION)") void setLaunchCookie(in IBinder launchCookie); } diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl index c259f9ad9cf9..c97265d4939d 100644 --- a/media/java/android/media/projection/IMediaProjectionManager.aidl +++ b/media/java/android/media/projection/IMediaProjectionManager.aidl @@ -28,11 +28,20 @@ interface IMediaProjectionManager { @UnsupportedAppUsage boolean hasProjectionPermission(int uid, String packageName); + /** + * Returns a new {@link IMediaProjection} instance associated with the given package. + */ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") IMediaProjection createProjection(int uid, String packageName, int type, boolean permanentGrant); + /** + * Returns {@code true} if the given {@link IMediaProjection} corresponds to the current + * projection, or {@code false} otherwise. + */ + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MANAGE_MEDIA_PROJECTION)") boolean isCurrentProjection(IMediaProjection projection); @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" @@ -67,6 +76,8 @@ interface IMediaProjectionManager { * @param incomingSession the nullable incoming content recording session * @param projection the non-null projection the session describes */ + @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + + ".permission.MANAGE_MEDIA_PROJECTION)") void setContentRecordingSession(in ContentRecordingSession incomingSession, in IMediaProjection projection); } diff --git a/media/java/android/media/soundtrigger/OWNERS b/media/java/android/media/soundtrigger/OWNERS index 01b2cb981bbb..85f7a4d605e6 100644 --- a/media/java/android/media/soundtrigger/OWNERS +++ b/media/java/android/media/soundtrigger/OWNERS @@ -1,2 +1,3 @@ +# Bug component: 48436 atneya@google.com elaurent@google.com diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index 2b7bcbee79fd..cc7a7d5bb9dc 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -161,7 +161,8 @@ public class CameraBinderTest extends AndroidTestCase { ICameraService.USE_CALLING_UID, ICameraService.USE_CALLING_PID, getContext().getApplicationInfo().targetSdkVersion, - /*overrideToPortrait*/false); + /*overrideToPortrait*/false, + /*forceSlowJpegMode*/false); assertNotNull(String.format("Camera %s was null", cameraId), cameraUser); Log.v(TAG, String.format("Camera %s connected", cameraId)); diff --git a/native/android/input.cpp b/native/android/input.cpp index f1c30889c4db..432e21cb5c08 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -149,7 +149,8 @@ int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointe } int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) { - return static_cast<const MotionEvent*>(motion_event)->getToolType(pointer_index); + const MotionEvent& motion = static_cast<const MotionEvent&>(*motion_event); + return static_cast<int32_t>(motion.getToolType(pointer_index)); } float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index) { diff --git a/packages/CarrierDefaultApp/res/values-ar/strings.xml b/packages/CarrierDefaultApp/res/values-ar/strings.xml index e8fa546d4a07..fe746f24912b 100644 --- a/packages/CarrierDefaultApp/res/values-ar/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ar/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string> <string name="android_system_label" msgid="2797790869522345065">"مُشغل شبكة الجوال"</string> <string name="portal_notification_id" msgid="5155057562457079297">"نفدت بيانات الجوّال"</string> <string name="no_data_notification_id" msgid="668400731803969521">"تم إيقاف بيانات الجوال"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"على سبيل المثال، قد لا تنتمي صفحة تسجيل الدخول إلى المؤسسة المعروضة."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"المتابعة على أي حال عبر المتصفح"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"تطبيق تعزيز الأداء"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"خيارات شبكة الجيل الخامس من مشغِّل شبكة الجوّال"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"يمكنك زيارة موقع %s الإلكتروني للاطّلاع على خيارات حول تجربة الاستخدام داخل التطبيق."</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"لاحقًا"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"إدارة"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"شراء تطبيق تعزيز الأداء"</string> diff --git a/packages/CarrierDefaultApp/res/values-be/strings.xml b/packages/CarrierDefaultApp/res/values-be/strings.xml index cd0974e03714..7ad11fb9153d 100644 --- a/packages/CarrierDefaultApp/res/values-be/strings.xml +++ b/packages/CarrierDefaultApp/res/values-be/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Аператар сувязі"</string> <string name="android_system_label" msgid="2797790869522345065">"Аператар мабільнай сувязі"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Мабільныя даныя скончыліся"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Перадача мабільных даных была дэактывавана"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Напрыклад, старонка ўваходу можа не належаць указанай арганізацыі."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Усё роўна працягнуць праз браўзер"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Павышэнне прадукцыйнасці"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Сувязь 5G ад аператара"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Каб паглядзець даступныя варыянты, наведайце вэб-сайт аператара \"%s\""</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не цяпер"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Кіраваць"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Аплаціце павышэнне прадукцыйнасці."</string> diff --git a/packages/CarrierDefaultApp/res/values-cs/strings.xml b/packages/CarrierDefaultApp/res/values-cs/strings.xml index 8ede78a8a42a..5fe8afba2f93 100644 --- a/packages/CarrierDefaultApp/res/values-cs/strings.xml +++ b/packages/CarrierDefaultApp/res/values-cs/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Komunikace s operátorem"</string> <string name="android_system_label" msgid="2797790869522345065">"Mobilní operátor"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Mobilní data byla vyčerpána"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Mobilní data byla deaktivována"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Přihlašovací stránka například nemusí patřit zobrazované organizaci."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Přesto pokračovat prostřednictvím prohlížeče"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Zvýšení výkonu"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Možnosti 5G od vašeho operátora"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Navštivte web operátora %s a podívejte se na možnosti pro vaši aplikaci"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Teď ne"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Spravovat"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupte si zvýšení výkonu."</string> diff --git a/packages/CarrierDefaultApp/res/values-da/strings.xml b/packages/CarrierDefaultApp/res/values-da/strings.xml index 57f8b1a2bb62..4a366953fa84 100644 --- a/packages/CarrierDefaultApp/res/values-da/strings.xml +++ b/packages/CarrierDefaultApp/res/values-da/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Kommunikation fra mobilselskab"</string> <string name="android_system_label" msgid="2797790869522345065">"Mobilselskab"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Der er ikke mere mobildata"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Mobildata er blevet deaktiveret"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Det er f.eks. ikke sikkert, at loginsiden tilhører den anførte organisation."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsæt alligevel via browseren"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Ydeevneboost"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-valgmuligheder fra dit mobilselskab"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Gå til websitet for %s for at se valgmuligheder for din appoplevelse"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ikke nu"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Køb et ydeevneboost."</string> diff --git a/packages/CarrierDefaultApp/res/values-fi/strings.xml b/packages/CarrierDefaultApp/res/values-fi/strings.xml index fc51611b978f..d5a242407af6 100644 --- a/packages/CarrierDefaultApp/res/values-fi/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fi/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Operaattoriviestintä"</string> <string name="android_system_label" msgid="2797790869522345065">"Mobiilioperaattori"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Mobiilidata on loppunut."</string> <string name="no_data_notification_id" msgid="668400731803969521">"Mobiilidata poistettu käytöstä"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Kirjautumissivu ei välttämättä kuulu näytetylle organisaatiolle."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Jatka selaimen kautta"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Suorituskykyboosti"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Operaattorin 5G-vaihtoehdot"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Vieraile verkkosivustolla (%s) nähdäksesi sovelluskokemuksen vaihtoehdot"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ei nyt"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Muuta"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Osta suorituskykyboosti."</string> diff --git a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml index 42dca42921f4..54dae628ba88 100644 --- a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Communications du fournisseur de services"</string> <string name="android_system_label" msgid="2797790869522345065">"Fournisseur de services"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Vous avez épuisé votre forfait de données cellulaires"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Les données cellulaires ont été désactivées pour votre compte"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion pourrait ne pas appartenir à l\'organisation représentée."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans un navigateur"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Optimiseur de performances"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Options 5G de votre fournisseur de services"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Consultez le site Web de %s pour voir les options concernant votre expérience de l\'application"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Plus tard"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gérer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Achetez un optimiseur de performances."</string> diff --git a/packages/CarrierDefaultApp/res/values-gl/strings.xml b/packages/CarrierDefaultApp/res/values-gl/strings.xml index ad2fdce9a9d6..6d3c85e435e4 100644 --- a/packages/CarrierDefaultApp/res/values-gl/strings.xml +++ b/packages/CarrierDefaultApp/res/values-gl/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Comunicacións do operador"</string> <string name="android_system_label" msgid="2797790869522345065">"Operador móbil"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Esgotáronse os datos móbiles"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Desactiváronse os datos móbiles"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, é posible que a páxina de inicio de sesión non pertenza á organización que se mostra."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar igualmente co navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Mellora de rendemento"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opcións de 5G do teu operador"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Vai ao sitio web de %s para ver as opcións relacionadas coa túa experiencia na aplicación"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora non"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Xestionar"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar unha mellora de rendemento."</string> diff --git a/packages/CarrierDefaultApp/res/values-hy/strings.xml b/packages/CarrierDefaultApp/res/values-hy/strings.xml index bca95a30dd7e..8cc0fc6f623f 100644 --- a/packages/CarrierDefaultApp/res/values-hy/strings.xml +++ b/packages/CarrierDefaultApp/res/values-hy/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string> <string name="android_system_label" msgid="2797790869522345065">"Բջջային օպերատոր"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Բջջային ինտերնետի սահմանաչափը սպառվել է"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Ձեր բջջային ինտերնետն ապակտիվացված է"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Օրինակ՝ մուտքի էջը կարող է ցուցադրված կազմակերպության էջը չլինել:"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Շարունակել դիտարկիչի միջոցով"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Արտադրողականության բարձրացում"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G ցանցով տարբերակներ՝ կապի օպերատորից"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Այցելեք %s-ի կայք՝ տեսնելու, թե ինչպես կարելի է բարձրացնել ձեր հավելվածի արդյունավետությունը"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ոչ հիմա"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Կառավարել"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Բարձրացրեք ցանցի արտադրողականությունը վճարի դիմաց։"</string> diff --git a/packages/CarrierDefaultApp/res/values-it/strings.xml b/packages/CarrierDefaultApp/res/values-it/strings.xml index f608ae97f0fb..82a5cab50250 100644 --- a/packages/CarrierDefaultApp/res/values-it/strings.xml +++ b/packages/CarrierDefaultApp/res/values-it/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Comunicazioni con l\'operatore"</string> <string name="android_system_label" msgid="2797790869522345065">"Operatore di telefonia mobile"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Dati mobili esauriti"</string> <string name="no_data_notification_id" msgid="668400731803969521">"I dati mobili sono stati disattivati"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Ad esempio, la pagina di accesso potrebbe non appartenere all\'organizzazione indicata."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continua comunque dal browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento di prestazioni"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opzioni 5G del tuo operatore"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visita il sito web di %s per vedere le opzioni di esperienza dell\'app"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Non ora"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestisci"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Acquista un aumento di prestazioni."</string> diff --git a/packages/CarrierDefaultApp/res/values-ja/strings.xml b/packages/CarrierDefaultApp/res/values-ja/strings.xml index 1fcbd7e5f834..2bcdaac5f020 100644 --- a/packages/CarrierDefaultApp/res/values-ja/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ja/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string> <string name="android_system_label" msgid="2797790869522345065">"携帯通信会社"</string> <string name="portal_notification_id" msgid="5155057562457079297">"モバイルデータの残量がありません"</string> <string name="no_data_notification_id" msgid="668400731803969521">"モバイルデータが無効になっています"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"たとえば、ログインページが表示されている組織に属していない可能性があります。"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ブラウザから続行"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"パフォーマンス ブースト"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"ご利用の携帯通信会社の 5G オプション"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"アプリのパフォーマンスを向上させるためのオプションを確認するには、%s のウェブサイトにアクセスしてください"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"後で"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"パフォーマンス ブーストを購入してください。"</string> diff --git a/packages/CarrierDefaultApp/res/values-nb/strings.xml b/packages/CarrierDefaultApp/res/values-nb/strings.xml index e001e44e3671..c50b4d37e77b 100644 --- a/packages/CarrierDefaultApp/res/values-nb/strings.xml +++ b/packages/CarrierDefaultApp/res/values-nb/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Operatørkommunikasjon"</string> <string name="android_system_label" msgid="2797790869522345065">"Mobiloperatør"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Du er tom for mobildata"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Mobildata er deaktivert"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Det er for eksempel mulig at påloggingssiden ikke tilhører organisasjonen som vises."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsett likevel via nettleseren"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Bedre ytelse"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-alternativer fra operatøren"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Gå til nettstedet til %s for å se alternativer for opplevelsen i appen"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ikke nå"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kjøp bedre ytelse."</string> diff --git a/packages/CarrierDefaultApp/res/values-pa/strings.xml b/packages/CarrierDefaultApp/res/values-pa/strings.xml index c9fd0e801b70..3cc81d426e29 100644 --- a/packages/CarrierDefaultApp/res/values-pa/strings.xml +++ b/packages/CarrierDefaultApp/res/values-pa/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"ਕੈਰੀਅਰ ਸੰਚਾਰ"</string> <string name="android_system_label" msgid="2797790869522345065">"ਮੋਬਾਈਲ ਕੈਰੀਅਰ"</string> <string name="portal_notification_id" msgid="5155057562457079297">"ਮੋਬਾਈਲ ਡਾਟਾ ਖਤਮ ਹੋ ਗਿਆ ਹੈ"</string> <string name="no_data_notification_id" msgid="668400731803969521">"ਤੁਹਾਡਾ ਮੋਬਾਈਲ ਡਾਟਾ ਅਕਿਰਿਆਸ਼ੀਲ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ਉਦਾਹਰਣ ਵੱਜੋਂ, ਲੌਗ-ਇਨ ਪੰਨਾ ਦਿਖਾਈ ਗਈ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਨਹੀਂ ਹੋ ਸਕਦਾ ਹੈ।"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ਬ੍ਰਾਊਜ਼ਰ ਰਾਹੀਂ ਫਿਰ ਵੀ ਜਾਰੀ ਰੱਖੋ"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"ਕਾਰਗੁਜ਼ਾਰੀ ਬੂਸਟ"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਤੋਂ 5G ਵਿਕਲਪ"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"ਆਪਣੇ ਐਪ ਅਨੁਭਵ ਲਈ ਵਿਕਲਪ ਦੇਖਣ ਵਾਸਤੇ %s ਦੀ ਵੈੱਬਸਾਈਟ \'ਤੇ ਜਾਓ"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ਹੁਣੇ ਨਹੀਂ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ਕਾਰਗੁਜ਼ਾਰੀ ਬੂਸਟ ਖਰੀਦੋ।"</string> diff --git a/packages/CarrierDefaultApp/res/values-si/strings.xml b/packages/CarrierDefaultApp/res/values-si/strings.xml index 6a8ce71abe00..cdf270e42849 100644 --- a/packages/CarrierDefaultApp/res/values-si/strings.xml +++ b/packages/CarrierDefaultApp/res/values-si/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"වාහක සන්නිවේදනය"</string> <string name="android_system_label" msgid="2797790869522345065">"ජංගම වාහකය"</string> <string name="portal_notification_id" msgid="5155057562457079297">"ජංගම දත්ත අවසන් වී ඇත"</string> <string name="no_data_notification_id" msgid="668400731803969521">"ඔබගේ ජංගම දත්ත අක්රිය කර ඇත"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"උදාහරණයක් ලෙස, පුරනය වන පිටුව පෙන්වා ඇති සංවිධානයට අයිති නැති විය හැක."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"කෙසේ වුවත් බ්රවුසරය හරහා ඉදිරියට යන්න"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"කාර්ය සාධනය ඉහළ නැංවීම"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"ඔබේ වාහකයෙන් 5G විකල්ප"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"ඔබේ යෙදුම් අත්දැකීම සඳහා විකල්ප බැලීමට %sගේ වෙබ් අඩවියට පිවිසෙන්න"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"දැන් නොවේ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"කළමනාකරණය කරන්න"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"කාර්ය සාධනය ඉහළ නැංවීමක් මිල දී ගන්න."</string> diff --git a/packages/CarrierDefaultApp/res/values-ta/strings.xml b/packages/CarrierDefaultApp/res/values-ta/strings.xml index 4916854ce8b9..48d6ff33dc44 100644 --- a/packages/CarrierDefaultApp/res/values-ta/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ta/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string> <string name="android_system_label" msgid="2797790869522345065">"தொலைத்தொடர்பு நிறுவனம்"</string> <string name="portal_notification_id" msgid="5155057562457079297">"மொபைல் டேட்டா தீர்ந்துவிட்டது"</string> <string name="no_data_notification_id" msgid="668400731803969521">"மொபைல் டேட்டா முடக்கப்பட்டது"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"எடுத்துக்காட்டாக, உள்நுழைவுப் பக்கமானது காட்டப்படும் அமைப்பிற்குச் சொந்தமானதாக இல்லாமல் இருக்கலாம்."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"பரவாயில்லை, உலாவி வழியாகத் தொடர்க"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"பெர்ஃபார்மென்ஸ் பூஸ்ட்"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"உங்கள் மொபைல் நெட்வொர்க் நிறுவனம் வழங்கும் 5G விருப்பத்தேர்வுகள்"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"உங்கள் ஆப்ஸ் அனுபவத்திற்கான விருப்பத்தேர்வுகளைப் பார்க்க %s இணையதளத்திற்குச் செல்லுங்கள்"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"இப்போது வேண்டாம்"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"நிர்வகியுங்கள்"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ஒரு பெர்ஃபார்மென்ஸ் பூஸ்ட்டைப் பர்ச்சேஸ் செய்யுங்கள்."</string> diff --git a/packages/CarrierDefaultApp/res/values-tr/strings.xml b/packages/CarrierDefaultApp/res/values-tr/strings.xml index e58d6798b85c..49b0f722f8e2 100644 --- a/packages/CarrierDefaultApp/res/values-tr/strings.xml +++ b/packages/CarrierDefaultApp/res/values-tr/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Operatör İletişimleri"</string> <string name="android_system_label" msgid="2797790869522345065">"Mobil Operatör"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Mobil veri kotanız tükendi"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Mobil veriniz devre dışı bırakıldı"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Örneğin, giriş sayfası, gösterilen kuruluşa ait olmayabilir."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Yine de tarayıcıyla devam et"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performans artışı"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Operatörünüzün 5G seçenekleri"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Uygulama deneyiminizle ilgili seçenekleri görmek için %s web sitesini ziyaret edin"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Şimdi değil"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Yönet"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Performans artışı satın alın."</string> diff --git a/packages/CarrierDefaultApp/res/values-uk/strings.xml b/packages/CarrierDefaultApp/res/values-uk/strings.xml index deac7bb4ffa5..ecd1182b85d4 100644 --- a/packages/CarrierDefaultApp/res/values-uk/strings.xml +++ b/packages/CarrierDefaultApp/res/values-uk/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"Сповіщення оператора"</string> <string name="android_system_label" msgid="2797790869522345065">"Оператор мобільного зв’язку"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Мобільний трафік вичерпано"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Мобільний трафік дезактивовано"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Наприклад, сторінка входу може не належати вказаній організації."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Усе одно продовжити у веб-переглядачі"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Підвищення продуктивності"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"Варіанти 5G від вашого оператора"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Перейдіть на веб-сайт %s, щоб переглянути варіанти взаємодії з додатком"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не зараз"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Керувати"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Придбайте підвищення продуктивності."</string> diff --git a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml index ce51495bad71..e8a679c11e91 100644 --- a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"流動網絡供應商最新消息"</string> <string name="android_system_label" msgid="2797790869522345065">"流動網絡供應商"</string> <string name="portal_notification_id" msgid="5155057562457079297">"流動數據量已用盡"</string> <string name="no_data_notification_id" msgid="668400731803969521">"您的流動數據已停用"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"例如,登入頁面可能並不屬於所顯示的機構。"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"效能提升服務"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"流動網絡供應商提供的 5G 選項"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"瀏覽「%s」網站即可查看應用程式體驗選項"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"暫時不要"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"購買效能提升服務。"</string> diff --git a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml index db3e4db094c9..6108247db1f5 100644 --- a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- no translation found for app_name (2809080280462257271) --> - <skip /> + <string name="app_name" msgid="2809080280462257271">"電信業者最新消息"</string> <string name="android_system_label" msgid="2797790869522345065">"電信業者"</string> <string name="portal_notification_id" msgid="5155057562457079297">"行動數據已用盡"</string> <string name="no_data_notification_id" msgid="668400731803969521">"你的行動數據已停用"</string> @@ -16,10 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"例如,登入網頁中顯示的機構可能並非該網頁實際隸屬的機構。"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"效能提升方案"</string> - <!-- no translation found for performance_boost_notification_title (3126203390685781861) --> - <skip /> - <!-- no translation found for performance_boost_notification_detail (216569851036236346) --> - <skip /> + <string name="performance_boost_notification_title" msgid="3126203390685781861">"你的電信業者推出的 5G 方案"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"造訪「%s」網站,瞭解如要享有優質應用程式體驗,可選用哪些方案"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"暫時不要"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"購買效能提升方案。"</string> diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml index 873c6029eec7..4b864d3614f7 100644 --- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml @@ -41,7 +41,7 @@ <string name="summary_generic_single_device" msgid="4735072202474939111">"This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> <string name="summary_generic" msgid="4988130802522924650">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device."</string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> - <string name="consent_no" msgid="2640796915611404382">"Don’t allow"</string> + <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string> <string name="consent_back" msgid="2560683030046918882">"Back"</string> <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on <strong><xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g></strong> the same permissions as on <strong><xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="permission_sync_summary" msgid="765497944331294275">"This may include <strong>Microphone</strong>, <strong>Camera</strong>, and <strong>Location access</strong>, and other sensitive permissions on <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong>. <br/><br/>You can change these permissions any time in your Settings on <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong>."</string> diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml index 82e5a7f0682a..c898fe5a9f2c 100644 --- a/packages/CompanionDeviceManager/res/values/strings.xml +++ b/packages/CompanionDeviceManager/res/values/strings.xml @@ -31,10 +31,10 @@ <string name="chooser_title">Choose a <xliff:g id="profile_name" example="watch">%1$s</xliff:g> to be managed by <strong><xliff:g id="app_name" example="Android Wear">%2$s</xliff:g></strong></string> <!-- Description of the privileges the application will get if associated with the companion device of WATCH profile (type) [CHAR LIMIT=NONE] --> - <string name="summary_watch">The app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.</string> + <string name="summary_watch">This app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.</string> <!-- Description of the privileges the application will get if associated with the companion device of WATCH profile for singleDevice(type) [CHAR LIMIT=NONE] --> - <string name="summary_watch_single_device">The app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, and access these permissions:</string> + <string name="summary_watch_single_device">This app will be allowed to sync info, like the name of someone calling, and access these permissions</string> <!-- ================= DEVICE_PROFILE_GLASSES ================= --> @@ -48,7 +48,7 @@ <string name="summary_glasses_multi_device">This app is needed to manage <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions.</string> <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile for singleDevice(type) [CHAR LIMIT=NONE] --> - <string name="summary_glasses_single_device">This app will be allowed to access these permissions on your phone:</string> + <string name="summary_glasses_single_device">This app will be allowed to access these permissions on your phone</string> <!-- ================= DEVICE_PROFILE_APP_STREAMING ================= --> @@ -97,10 +97,10 @@ <string name="profile_name_generic">device</string> <!-- Description of the privileges the application will get if associated with the companion device of unspecified profile (type) [CHAR LIMIT=NONE] --> - <string name="summary_generic_single_device">This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>.</string> + <string name="summary_generic_single_device">This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="device_name" example="My Watch">%1$s</xliff:g></string> <!-- Description of the privileges the application will get if associated with the companion device of unspecified profile (type) [CHAR LIMIT=NONE] --> - <string name="summary_generic">This app will be able to sync info, like the name of someone calling, between your phone and the chosen device.</string> + <string name="summary_generic">This app will be able to sync info, like the name of someone calling, between your phone and the chosen device</string> <!-- ================= Buttons ================= --> diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java index 71ae578ec310..ae0882342be4 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java @@ -551,8 +551,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements summary = getHtmlFromResources(this, SUMMARIES.get(null), deviceName); mConstraintList.setVisibility(View.GONE); } else { - summary = getHtmlFromResources(this, SUMMARIES.get(deviceProfile), - getString(PROFILES_NAME.get(deviceProfile)), appLabel); + summary = getHtmlFromResources(this, SUMMARIES.get(deviceProfile)); mPermissionTypes.addAll(PERMISSION_TYPES.get(deviceProfile)); setupPermissionList(); } diff --git a/packages/CredentialManager/AndroidManifest.xml b/packages/CredentialManager/AndroidManifest.xml index dfc8aa06c404..8724d69258ed 100644 --- a/packages/CredentialManager/AndroidManifest.xml +++ b/packages/CredentialManager/AndroidManifest.xml @@ -19,6 +19,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.credentialmanager"> + <uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/> diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml index 6b621ce73492..b4e22fd23bff 100644 --- a/packages/CredentialManager/res/values-af/strings.xml +++ b/packages/CredentialManager/res/values-af/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gebruik jou gestoorde wagwoordsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gebruik jou gestoorde aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Kies ’n gestoorde aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Meld op ’n ander manier aan"</string> <string name="snackbar_action" msgid="37373514216505085">"Bekyk opsies"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Gaan voort"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Bestuur aanmeldings"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Van ’n ander toestel af"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gebruik ’n ander toestel"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml index 6b00e083131f..19a80a5e9610 100644 --- a/packages/CredentialManager/res/values-am/strings.xml +++ b/packages/CredentialManager/res/values-am/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"የተቀመጠ የይለፍ ቁልፍዎን ለ<xliff:g id="APP_NAME">%1$s</xliff:g> ይጠቀሙ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"የተቀመጠ መግቢያዎን ለ<xliff:g id="APP_NAME">%1$s</xliff:g> ይጠቀሙ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"ለ<xliff:g id="APP_NAME">%1$s</xliff:g> የተቀመጠ መግቢያ ይጠቀሙ"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"በሌላ መንገድ ይግቡ"</string> <string name="snackbar_action" msgid="37373514216505085">"አማራጮችን አሳይ"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ቀጥል"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"መግቢያዎችን ያስተዳድሩ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ከሌላ መሣሪያ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"የተለየ መሣሪያ ይጠቀሙ"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml index 2d6a606163b7..ec62751ba5ec 100644 --- a/packages/CredentialManager/res/values-ar/strings.xml +++ b/packages/CredentialManager/res/values-ar/strings.xml @@ -26,7 +26,7 @@ <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"هل تريد إنشاء مفتاح مرور لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"هل تريد حفظ كلمة المرور لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"هل تريد حفظ معلومات تسجيل الدخول لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string> - <string name="passkey" msgid="632353688396759522">"مفتاح مرور"</string> + <string name="passkey" msgid="632353688396759522">"مفتاح المرور"</string> <string name="password" msgid="6738570945182936667">"كلمة المرور"</string> <string name="passkeys" msgid="5733880786866559847">"مفاتيح المرور"</string> <string name="passwords" msgid="5419394230391253816">"كلمات المرور"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"هل تريد استخدام مفتاح المرور المحفوظ لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"هل تريد استخدام بيانات اعتماد تسجيل الدخول المحفوظة لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"اختيار بيانات اعتماد تسجيل دخول محفوظة لـ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"تسجيل الدخول بطريقة أخرى"</string> <string name="snackbar_action" msgid="37373514216505085">"عرض الخيارات"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"متابعة"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"إداراة عمليات تسجيل الدخول"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"من جهاز آخر"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استخدام جهاز مختلف"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml index 8c5e6372d399..41eba93b1e60 100644 --- a/packages/CredentialManager/res/values-as/strings.xml +++ b/packages/CredentialManager/res/values-as/strings.xml @@ -16,7 +16,7 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"পাছৱৰ্ডবিহীন প্ৰযুক্তি"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"পাছকীসমূহে আপোনাক পাছৱৰ্ডৰ ওপৰত নিৰ্ভৰ নকৰাকৈ ছাইন ইন কৰাৰ অনুমতি দিয়ে। আপুনি আপোনাৰ পৰিচয় সত্যাপন কৰিবলৈ আৰু এটা পাছকী সৃষ্টি কৰিবলৈ কেৱল আপোনাৰ ফিংগাৰপ্ৰিণ্ট, মুখাৱয়ব চিনাক্তকৰণ, পিন অথবা ছোৱাইপ কৰাৰ আৰ্হি ব্যৱহাৰ কৰিলেই হ’ল।"</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"ৰাজহুৱা চাবি ক্ৰিপ্ট’গ্ৰাফী"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO জোঁট (য’ত Google, Apple, Microsoft আৰু অধিক অন্তৰ্ভুক্ত) আৰু W3C মানকসমূহৰ ওপৰত ভিত্তি কৰি, পাছকীসমূহে ক্ৰিপ্ট’গ্ৰাফিক চাবিৰ যোৰা ব্যৱহাৰ কৰে। আমি পাছৱৰ্ডৰ বাবে ব্যৱহাৰ কৰা ব্যৱহাৰকাৰীৰ নাম আৰু বৰ্ণৰ ষ্ট্ৰিঙৰ বিপৰীতে, এটা এপ্ অথবা ৱেবছাইটৰ বাবে এটা ব্যক্তিগত-ৰাজহুৱা কীৰ যোৰা সৃষ্টি কৰা হয়। ব্যক্তিগত চাবিটো আপোনাৰ ডিভাইচ অথবা পাছৱৰ্ড পৰিচালকত সুৰক্ষিতভাৱে ষ্ট’ৰ কৰা হয় আৰু ই আপোনাৰ পৰিচয় নিশ্চিত কৰে। ৰাজহুৱা চাবিটো এপ্ অথবা ৱেবছাইটৰ ছাৰ্ভাৰৰ সৈতে শ্বেয়াৰ কৰা হয়। সংশ্লিষ্ট চাবিসমূহৰ জৰিয়তে আপুনি তাৎক্ষণিকভাৱে পঞ্জীয়ন আৰু ছাইন ইন কৰিব পাৰিব।"</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO জোঁট (য’ত Google, Apple, Microsoft আৰু অধিক অন্তৰ্ভুক্ত) আৰু W3C মানকসমূহৰ ওপৰত ভিত্তি কৰি, পাছকীসমূহে ক্ৰিপ্ট’গ্ৰাফিক চাবিৰ যোৰা ব্যৱহাৰ কৰে। আমি পাছৱৰ্ডৰ বাবে ব্যৱহাৰ কৰা ব্যৱহাৰকাৰীৰ নাম আৰু বৰ্ণৰ ষ্ট্ৰিঙৰ বিপৰীতে, এটা এপ্ অথবা ৱেবছাইটৰ বাবে এটা ব্যক্তিগত-ৰাজহুৱা চাবিৰ যোৰা সৃষ্টি কৰা হয়। ব্যক্তিগত চাবিটো আপোনাৰ ডিভাইচ অথবা পাছৱৰ্ড পৰিচালকত সুৰক্ষিতভাৱে ষ্ট’ৰ কৰা হয় আৰু ই আপোনাৰ পৰিচয় নিশ্চিত কৰে। ৰাজহুৱা চাবিটো এপ্ অথবা ৱেবছাইটৰ ছাৰ্ভাৰৰ সৈতে শ্বেয়াৰ কৰা হয়। সংশ্লিষ্ট চাবিসমূহৰ জৰিয়তে আপুনি তাৎক্ষণিকভাৱে পঞ্জীয়ন আৰু ছাইন ইন কৰিব পাৰিব।"</string> <string name="improved_account_security_title" msgid="1069841917893513424">"একাউণ্টৰ উন্নত সুৰক্ষা"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"প্ৰতিটো চাবি বিশেষভাৱে সেই এপ্ অথবা ৱেবছাইটৰ সৈতে লিংক কৰা হয় যাৰ বাবে সেইটো সৃষ্টি কৰা হৈছে, সেয়ে আপুনি কেতিয়াও ভুলতে কোনো প্ৰৱঞ্চনামূলক এপ্ অথবা ৱেবছাইটত ছাইন ইন কৰিব নোৱাৰে। ইয়াৰ উপৰিও, কেৱল ৰাজহুৱা চাবিসমূহ ৰখা ছাৰ্ভাৰৰ ক্ষেত্ৰত হেক কৰাটো বহুত কঠিন হৈ পৰে।"</string> <string name="seamless_transition_title" msgid="5335622196351371961">"বাধাহীন স্থানান্তৰণ"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে আপোনাৰ ছেভ হৈ থকা পাছকী ব্যৱহাৰ কৰিবনে?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে আপোনাৰ ছেভ হৈ থকা ছাইন ইন তথ্য ব্যৱহাৰ কৰিবনে?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে ছেভ হৈ থকা এটা ছাইন ইন বাছনি কৰক"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"অন্য উপায়েৰে ছাইন ইন কৰক"</string> <string name="snackbar_action" msgid="37373514216505085">"বিকল্পসমূহ চাওক"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"অব্যাহত ৰাখক"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ছাইন ইন পৰিচালনা কৰক"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য এটা ডিভাইচৰ পৰা"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"অন্য এটা ডিভাইচ ব্যৱহাৰ কৰক"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml index e016760bbe3d..0c274f0d52ce 100644 --- a/packages/CredentialManager/res/values-az/strings.xml +++ b/packages/CredentialManager/res/values-az/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış giriş açarı istifadə edilsin?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış girişdən istifadə edilsin?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış girişi seçin"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Başqa üsulla daxil olun"</string> <string name="snackbar_action" msgid="37373514216505085">"Seçimlərə baxın"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Davam edin"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Girişləri idarə edin"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başqa cihazdan"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Başqa cihaz istifadə edin"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml index c80b17e55a59..adc2d0c0ed24 100644 --- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml @@ -21,7 +21,7 @@ <string name="improved_account_security_detail" msgid="9123750251551844860">"Svaki ključ je isključivo povezan sa aplikacijom ili veb-sajtom za koje je napravljen, pa nikad ne možete greškom da se prijavite u aplikaciju ili na veb-sajt koji služe za prevaru. Osim toga, sa serverima koji čuvaju samo javne ključeve hakovanje je mnogo teže."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Besprekoran prelaz"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"Kako se krećemo ka budućnosti bez lozinki, lozinke će i dalje biti dostupne uz pristupne kodove"</string> - <string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gde ćete sačuvati stavke <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> + <string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gde ćete sačuvati: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Izaberite menadžera lozinki da biste sačuvali podatke i brže se prijavili sledeći put"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Želite da napravite pristupni kôd za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"Želite da sačuvate lozinku za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -32,7 +32,7 @@ <string name="passwords" msgid="5419394230391253816">"lozinke"</string> <string name="sign_ins" msgid="4710739369149469208">"prijavljivanja"</string> <string name="sign_in_info" msgid="2627704710674232328">"podaci za prijavljivanje"</string> - <string name="save_credential_to_title" msgid="3172811692275634301">"Sačuvaj stavku <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> u"</string> + <string name="save_credential_to_title" msgid="3172811692275634301">"Sačuvaj <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> u"</string> <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Želite da napravite pristupni kôd na drugom uređaju?"</string> <string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite da za sva prijavljivanja koristite: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string> <string name="use_provider_for_all_description" msgid="1998772715863958997">"Ovaj menadžer lozinki za <xliff:g id="USERNAME">%1$s</xliff:g> će čuvati lozinke i pristupne kodove da biste se lako prijavljivali"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite da koristite sačuvani pristupni kôd za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite da koristite sačuvane podatke za prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Odaberite sačuvano prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijavite se na drugi način"</string> <string name="snackbar_action" msgid="37373514216505085">"Prikaži opcije"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Nastavi"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljajte prijavljivanjima"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Sa drugog uređaja"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Koristi drugi uređaj"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml index 13a329a88d54..50c4f721a56c 100644 --- a/packages/CredentialManager/res/values-be/strings.xml +++ b/packages/CredentialManager/res/values-be/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Скарыстаць захаваны ключ доступу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Скарыстаць захаваныя спосабы ўваходу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Выберыце захаваны спосаб уваходу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Увайсці іншым спосабам"</string> <string name="snackbar_action" msgid="37373514216505085">"Праглядзець варыянты"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Далей"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кіраваць спосабамі ўваходу"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншай прылады"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Скарыстаць іншую прыладу"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml index 453c58f7d883..ec4732accf0f 100644 --- a/packages/CredentialManager/res/values-bg/strings.xml +++ b/packages/CredentialManager/res/values-bg/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Да се използва ли запазеният ви код за достъп за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Да се използват ли запазените ви данни за вход за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Изберете запазени данни за вход за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Влизане в профила по друг начин"</string> <string name="snackbar_action" msgid="37373514216505085">"Преглед на опциите"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Напред"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управление на данните за вход"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"От друго устройство"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Използване на друго устройство"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml index 8360931eb750..021c80c3d7a5 100644 --- a/packages/CredentialManager/res/values-bn/strings.xml +++ b/packages/CredentialManager/res/values-bn/strings.xml @@ -44,7 +44,7 @@ <string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g>টি ক্রেডেনশিয়াল"</string> <string name="passkey_before_subtitle" msgid="2448119456208647444">"পাসকী"</string> <string name="another_device" msgid="5147276802037801217">"অন্য ডিভাইস"</string> - <string name="other_password_manager" msgid="565790221427004141">"অন্যান্য Password Manager"</string> + <string name="other_password_manager" msgid="565790221427004141">"অন্যান্য পাসওয়ার্ড ম্যানেজার"</string> <string name="close_sheet" msgid="1393792015338908262">"শিট বন্ধ করুন"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"আগের পৃষ্ঠায় ফিরে যান"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"বন্ধ করুন"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য আপনার সেভ করা পাসকী ব্যবহার করবেন?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য আপনার সেভ করা সাইন-ইন সম্পর্কিত ক্রেডেনশিয়াল ব্যবহার করবেন?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য সাইন-ইন করা সম্পর্কিত ক্রেডেনশিয়াল বেছে নিন"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"অন্যভাবে সাইন-ইন করুন"</string> <string name="snackbar_action" msgid="37373514216505085">"বিকল্প দেখুন"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"চালিয়ে যান"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"সাইন-ইন করার ক্রেডেনশিয়াল ম্যানেজ করুন"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য ডিভাইস থেকে"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"আলাদা ডিভাইস ব্যবহার করুন"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml index e37232d22be7..897d016889ed 100644 --- a/packages/CredentialManager/res/values-bs/strings.xml +++ b/packages/CredentialManager/res/values-bs/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Koristiti sačuvani pristupni ključ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Koristiti sačuvanu prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Odaberite sačuvanu prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijavite se na drugi način"</string> <string name="snackbar_action" msgid="37373514216505085">"Prikaži opcije"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Nastavi"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljajte prijavama"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"S drugog uređaja"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je otkazala zahtjev"</string> </resources> diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml index aed1610cee4f..7d0f568ae20b 100644 --- a/packages/CredentialManager/res/values-ca/strings.xml +++ b/packages/CredentialManager/res/values-ca/strings.xml @@ -20,7 +20,7 @@ <string name="improved_account_security_title" msgid="1069841917893513424">"Seguretat dels comptes millorada"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Cada clau està exclusivament enllaçada a l\'aplicació o al lloc web per als quals s\'ha creat. D\'aquesta manera, mai iniciaràs la sessió en una aplicació o un lloc web fraudulents per error. A més, com que els servidors només conserven les claus públiques, el hacking és molt més difícil."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Transició fluida"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Tot i que avancem cap a un futur sense contrasenyes, continuaran estant disponibles juntament amb les claus d\'accés"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Tot i que avancem cap a un futur sense contrasenyes, continuaran estant disponibles juntament amb les claus d\'accés."</string> <string name="choose_provider_title" msgid="8870795677024868108">"Tria on vols desar les <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un gestor de contrasenyes per desar la teva informació i iniciar la sessió més ràpidament la pròxima vegada"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vols crear la clau d\'accés per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vols utilitzar la clau d\'accés desada per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vols utilitzar l\'inici de sessió desat per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Tria un inici de sessió desat per a <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Inicia la sessió d\'una altra manera"</string> <string name="snackbar_action" msgid="37373514216505085">"Mostra les opcions"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continua"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestiona els inicis de sessió"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Des d\'un altre dispositiu"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utilitza un dispositiu diferent"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml index 8eb0ff6a6f96..498e86e01433 100644 --- a/packages/CredentialManager/res/values-cs/strings.xml +++ b/packages/CredentialManager/res/values-cs/strings.xml @@ -16,7 +16,7 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"Technologie bez hesel"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Přístupové klíče umožňují přihlašovat se bez hesel. Stačí pomocí otisku prstu, rozpoznání obličeje, kódu PIN nebo gesta ověřit svou totožnost a vytvořit přístupový klíč."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kryptografie s veřejným klíčem"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Podle pokynů FIDO Alliance (která zahrnuje společnosti Google, Apple, Microsoft a další) a standardů W3C používají přístupové klíče páry kryptografických klíčů. Na rozdíl od uživatelského jména a řetězce znaků, které používáme pro hesla, se pro aplikaci nebo web vytváří pár klíčů (soukromého a veřejného ). Soukromý klíč je bezpečně uložen ve vašem zařízení nebo správci hesel a potvrzuje vaši identitu. Veřejný klíč je sdílen s aplikací nebo webovým serverem. Pomocí odpovídajících klíčů se můžete okamžitě zaregistrovat a přihlásit."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Podle pokynů FIDO Alliance (která zahrnuje společnosti Google, Apple, Microsoft a další) a standardů W3C používají přístupové klíče páry kryptografických klíčů. Na rozdíl od uživatelského jména a řetězce znaků, které používáme pro hesla, se pro aplikaci nebo web vytváří pár klíčů (soukromého a veřejného). Soukromý klíč je bezpečně uložen ve vašem zařízení nebo správci hesel a potvrzuje vaši identitu. Veřejný klíč je sdílen s aplikací nebo webovým serverem. Pomocí odpovídajících klíčů se můžete okamžitě zaregistrovat a přihlásit."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Vylepšené zabezpečení účtu"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Každý klíč je propojen výhradně s aplikací nebo webem, pro které byl vytvořen, takže se nikdy nemůžete omylem přihlásit k podvodné aplikaci nebo webu. Protože na serverech jsou uloženy pouze veřejné klíče, je hackování navíc mnohem obtížnější."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Bezproblémový přechod"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Použít uložený přístupový klíč pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Použít uložené přihlášení pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Vyberte uložené přihlášení pro <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Přihlásit se jinak"</string> <string name="snackbar_action" msgid="37373514216505085">"Zobrazit možnosti"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Pokračovat"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Spravovat přihlášení"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z jiného zařízení"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použít jiné zařízení"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml index 8e24cc9f4f48..8ab42949546a 100644 --- a/packages/CredentialManager/res/values-da/strings.xml +++ b/packages/CredentialManager/res/values-da/strings.xml @@ -20,7 +20,7 @@ <string name="improved_account_security_title" msgid="1069841917893513424">"Forbedret kontosikkerhed"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Hver nøgle er udelukkende tilknyttet den app eller det website, som nøglen blev oprettet til. På denne måde kan du aldrig logge ind i en svigagtig app eller på et svigagtigt website ved en fejl. Og da serverne kun opbevarer offentlige nøgler, er kontoer meget sværere at hacke."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Problemfri overgang"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Selvom vi nærmer os en fremtid, hvor adgangskoder er mindre fremtrædende, kan de stadig bruges i samspil med adgangsnøgler"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Selvom vi nærmer os en fremtid, hvor adgangskoder er mindre fremtrædende, kan de stadig bruges i samspil med adgangsnøgler."</string> <string name="choose_provider_title" msgid="8870795677024868108">"Vælg, hvor du vil gemme dine <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Vælg en adgangskodeadministrator for at gemme dine oplysninger, så du kan logge ind hurtigere næste gang"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vil du oprette en adgangsnøgle til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruge din gemte adgangsnøgle til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vil du bruge din gemte loginmetode til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Vælg en gemt loginmetode til <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Log ind på en anden måde"</string> <string name="snackbar_action" msgid="37373514216505085">"Se valgmuligheder"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Fortsæt"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrer loginmetoder"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en anden enhed"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Brug en anden enhed"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml index 8c9138c55399..9e943edb262a 100644 --- a/packages/CredentialManager/res/values-de/strings.xml +++ b/packages/CredentialManager/res/values-de/strings.xml @@ -9,8 +9,8 @@ <string name="content_description_show_password" msgid="3283502010388521607">"Passwort einblenden"</string> <string name="content_description_hide_password" msgid="6841375971631767996">"Passwort ausblenden"</string> <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Mehr Sicherheit mit Passkeys"</string> - <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Mit Passkeys musst du keine komplizierten Passwörter erstellen oder dir merken"</string> - <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys sind verschlüsselte digitale Schlüssel, die du mithilfe deines Fingerabdrucks, Gesichts oder deiner Displaysperre erstellst"</string> + <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Mit Passkeys musst du keine komplizierten Passwörter erstellen oder sie dir merken"</string> + <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Passkeys sind verschlüsselte digitale Schlüssel, die du mithilfe deines Fingerabdrucks, der Gesichtserkennung oder deiner Displaysperre erstellst"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Sie werden in einem Passwortmanager gespeichert, damit du dich auf anderen Geräten anmelden kannst"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Weitere Informationen zu Passkeys"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Passwortlose Technologie"</string> @@ -20,7 +20,7 @@ <string name="improved_account_security_title" msgid="1069841917893513424">"Verbesserte Kontosicherheit"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Jeder Schlüssel ist ausschließlich mit der App oder Website verknüpft, für die er erstellt wurde. Du kannst dich also nicht aus Versehen bei einer betrügerischen App oder Website anmelden. Da auf Servern nur öffentliche Schlüssel verwaltet werden, wird das Hacking außerdem erheblich erschwert."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Nahtlose Umstellung"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Auch wenn wir uns auf eine passwortlose Zukunft zubewegen, werden neben Passkeys weiter Passwörter verfügbar sein"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Auch wenn wir uns auf eine passwortlose Zukunft zubewegen, werden neben Passkeys weiter Passwörter verfügbar sein."</string> <string name="choose_provider_title" msgid="8870795677024868108">"Wähle aus, wo deine <xliff:g id="CREATETYPES">%1$s</xliff:g> gespeichert werden sollen"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Du kannst einen Passwortmanager auswählen, um deine Anmeldedaten zu speichern, damit du dich nächstes Mal schneller anmelden kannst"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Passkey für <xliff:g id="APPNAME">%1$s</xliff:g> erstellen?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gespeicherten Passkey für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gespeicherte Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Gespeicherte Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> auswählen"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Andere Anmeldeoption auswählen"</string> <string name="snackbar_action" msgid="37373514216505085">"Optionen ansehen"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Weiter"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Anmeldedaten verwalten"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Von einem anderen Gerät"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Anderes Gerät verwenden"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml index 71895850e58a..fae58e292604 100644 --- a/packages/CredentialManager/res/values-el/strings.xml +++ b/packages/CredentialManager/res/values-el/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Να χρησιμοποιηθεί το αποθηκευμένο κλειδί πρόσβασης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Να χρησιμοποιηθούν τα αποθηκευμένα στοιχεία σύνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Επιλογή αποθηκευμένων στοιχείων σύνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Σύνδεση με άλλον τρόπο"</string> <string name="snackbar_action" msgid="37373514216505085">"Προβολή επιλογών"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Συνέχεια"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Διαχείριση στοιχείων σύνδεσης"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Από άλλη συσκευή"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Χρήση διαφορετικής συσκευής"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Το αίτημα ακυρώθηκε από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml index 5a5480d23aa4..f87bee44ad5a 100644 --- a/packages/CredentialManager/res/values-en-rAU/strings.xml +++ b/packages/CredentialManager/res/values-en-rAU/strings.xml @@ -18,7 +18,7 @@ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters that we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website it was created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"As we move towards a passwordless future, passwords will still be available alongside passkeys"</string> <string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string> <string name="snackbar_action" msgid="37373514216505085">"View options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml index 23091e79bda9..f297bd924536 100644 --- a/packages/CredentialManager/res/values-en-rCA/strings.xml +++ b/packages/CredentialManager/res/values-en-rCA/strings.xml @@ -52,6 +52,7 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Choose an option for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string> <string name="snackbar_action" msgid="37373514216505085">"View options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string> @@ -64,4 +65,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml index 5a5480d23aa4..f87bee44ad5a 100644 --- a/packages/CredentialManager/res/values-en-rGB/strings.xml +++ b/packages/CredentialManager/res/values-en-rGB/strings.xml @@ -18,7 +18,7 @@ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters that we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website it was created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"As we move towards a passwordless future, passwords will still be available alongside passkeys"</string> <string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string> <string name="snackbar_action" msgid="37373514216505085">"View options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml index 5a5480d23aa4..f87bee44ad5a 100644 --- a/packages/CredentialManager/res/values-en-rIN/strings.xml +++ b/packages/CredentialManager/res/values-en-rIN/strings.xml @@ -18,7 +18,7 @@ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Public key cryptography"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Based on FIDO Alliance (which includes Google, Apple, Microsoft and more) and W3C standards, passkeys use cryptographic key pairs. Unlike the username and string of characters that we use for passwords, a private-public key pair is created for an app or website. The private key is safely stored on your device or password manager and it confirms your identity. The public key is shared with the app or website server. With corresponding keys, you can instantly register and sign in."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Improved account security"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website they were created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"Each key is exclusively linked with the app or website it was created for, so you can never sign in to a fraudulent app or website by mistake. Plus, with servers only keeping public keys, hacking is a lot harder."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Seamless transition"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"As we move towards a passwordless future, passwords will still be available alongside passkeys"</string> <string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string> <string name="snackbar_action" msgid="37373514216505085">"View options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml index 465fd2c5bef4..66cb1762b2a2 100644 --- a/packages/CredentialManager/res/values-en-rXC/strings.xml +++ b/packages/CredentialManager/res/values-en-rXC/strings.xml @@ -52,6 +52,7 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Choose an option for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string> <string name="snackbar_action" msgid="37373514216505085">"View options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string> @@ -64,4 +65,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml index 27356a08b38f..c4e68e0e21e7 100644 --- a/packages/CredentialManager/res/values-es-rUS/strings.xml +++ b/packages/CredentialManager/res/values-es-rUS/strings.xml @@ -14,9 +14,9 @@ <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Se guardan en un administrador de contraseñas para que puedas acceder en otros dispositivos"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Más información sobre las llaves de acceso"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Tecnología sin contraseñas"</string> - <string name="passwordless_technology_detail" msgid="6853928846532955882">"Las llaves de acceso permiten acceder sin depender de contraseñas. Solo tienes que usar tu huella dactilar, reconocimiento facial, PIN o patrón de deslizamiento para verificar tu identidad y crear una clave de acceso."</string> + <string name="passwordless_technology_detail" msgid="6853928846532955882">"Las llaves de acceso permiten acceder sin depender de contraseñas. Solo tienes que usar tu huella dactilar, reconocimiento facial, PIN o patrón de deslizamiento para verificar tu identidad y crear una llave de acceso."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Criptografía de claves públicas"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Basadas en la Alianza FIDO (Google, Apple, Microsoft, etc.) y en estándares del W3C, las llaves de acceso usan pares de claves criptográficas. A diferencia de la cadena de caracteres de las contraseñas, para una app o sitio web se crean claves privadas y públicas. La clave privada se guarda en tu dispositivo/administrador de contraseñas, y confirma tu identidad. La clave pública se comparte con el servidor de la app o sitio web. Las claves adecuadas te permiten registrarte y acceder al instante."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Basadas en la Alianza FIDO (que incluye a Google, Apple, Microsoft, etc.) y en estándares del W3C, las llaves de acceso usan pares de claves criptográficas. A diferencia del nombre de usuario y la cadena de caracteres de las contraseñas, para una app o sitio web se crean claves privadas y públicas. La clave privada se guarda en tu dispositivo/administrador de contraseñas, y confirma tu identidad. La clave pública se comparte con el servidor de la app o sitio web. Las claves adecuadas te permiten registrarte y acceder al instante."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Mayor seguridad para las cuentas"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Cada llave está vinculada exclusivamente con el sitio web o la app para la que fue creada, por lo que nunca podrás acceder por error a una app o sitio web fraudulentos. Además, como los servidores solo guardan claves públicas, hackearlas es mucho más difícil."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Transición fluida"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Quieres usar tu llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"¿Quieres usar tu acceso guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Elige un acceso guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Acceder de otra forma"</string> <string name="snackbar_action" msgid="37373514216505085">"Ver opciones"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrar accesos"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Desde otro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otra voz"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> canceló la solicitud"</string> </resources> diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml index ebdb00d00ae1..3cefa6c67983 100644 --- a/packages/CredentialManager/res/values-es/strings.xml +++ b/packages/CredentialManager/res/values-es/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Usar la llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"¿Usar el inicio de sesión guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Elige un inicio de sesión guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Iniciar sesión de otra manera"</string> <string name="snackbar_action" msgid="37373514216505085">"Ver opciones"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionar inicios de sesión"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De otro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otro dispositivo"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml index 6d8b0326da53..4d577e78edfa 100644 --- a/packages/CredentialManager/res/values-et/strings.xml +++ b/packages/CredentialManager/res/values-et/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud pääsuvõtit?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud sisselogimisandmeid?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Valige rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud sisselogimisandmed"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Logige sisse muul viisil"</string> <string name="snackbar_action" msgid="37373514216505085">"Kuva valikud"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Jätka"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Sisselogimisandmete haldamine"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Muus seadmes"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Kasuta teist seadet"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml index 34a3e05f5a5d..1655cf5fc6b1 100644 --- a/packages/CredentialManager/res/values-eu/strings.xml +++ b/packages/CredentialManager/res/values-eu/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde duzun sarbide-gakoa erabili nahi duzu?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde dituzun kredentzialak erabili nahi dituzu?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde dituzun kredentzialak"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Hasi saioa beste modu batean"</string> <string name="snackbar_action" msgid="37373514216505085">"Ikusi aukerak"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Egin aurrera"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kudeatu kredentzialak"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Beste gailu batean gordetakoak"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Erabili beste gailu bat"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Utzi du bertan behera eskaera <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak"</string> </resources> diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml index 2407d100c5f9..81fef8a66d3d 100644 --- a/packages/CredentialManager/res/values-fa/strings.xml +++ b/packages/CredentialManager/res/values-fa/strings.xml @@ -13,16 +13,16 @@ <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"گذرکلیدها کلیدهای دیجیتالی رمزگذاریشدهای هستند که بااستفاده از اثر انگشت، چهره، یا قفل صفحه ایجاد میکنید"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"گذرکلیدها در «مدیر گذرواژه» ذخیره میشود تا بتوانید در دستگاههای دیگر به سیستم وارد شوید"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"اطلاعات بیشتر درباره گذرکلیدها"</string> - <string name="passwordless_technology_title" msgid="2497513482056606668">"فناوری بدون گذرواژه"</string> + <string name="passwordless_technology_title" msgid="2497513482056606668">"فناوری بیگذرواژه"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"گذرکلیدها به شما اجازه میدهند بدون اتکا به گذرواژه به سیستم وارد شوید. برای بهتأیید رساندن هویت خود و ایجاد گذرکلید، کافی است از اثر انگشت، تشخیص چهره، پین، یا الگوی کشیدنی استفاده کنید."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"رمزنگاری کلید عمومی"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"براساس «اتحاد FIDO» (که شامل Google، Apple، Microsoft، و غیره میشود) و استانداردهای W3C، گذرکلیدها از جفت کلیدهای رمزنگاریشده استفاده میکنند. برخلاف نام کاربری و رشته نویسههایی که برای گذرواژهها استفاده میکنیم، یک جفت کلید خصوصی-عمومی برای برنامه یا وبسایت ایجاد میشود. کلید خصوصی بهطور امن در دستگاه یا مدیر گذرواژه شما ذخیره میشود و هویت شما را تأیید میکند. کلید عمومی با سرور وبسایت یا برنامه همرسانی میشود. با کلیدهای مربوطه میتوانید بیدرنگ ثبتنام کنید و به سیستم وارد شوید."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"بهبود امنیت حساب"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"هر کلید با برنامه یا وبسایتی که برای آن ایجاد شده است پیوند انحصاری دارد، بنابراین هرگز نمیتوانید بهاشتباه به سیستم برنامه یا وبسایتی جعلی وارد شوید. بهعلاوه، با سرورهایی که فقط کلیدهای عمومی را نگه میدارند رخنهگری بسیار سختتر است."</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"هر کلید منحصراً با برنامه یا وبسایتی که برای آن ایجاد شده است پیوند داده میشود، بنابراین هرگز نمیتوانید به اشتباه وارد برنامه یا وبسایت تقلبی شوید. بهعلاوه، باتوجهبه اینکه سرورها فقط کلیدهای عمومی را نگه میدارند، رخنهگری (هک کردن) بسیار سختتر است."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"انتقال یکپارچه"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"درحالیکه بهسوی آیندهای بدون گذرواژه حرکت میکنیم، گذرواژهها همچنان در کنار گذرکلیدها دردسترس خواهند بود"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"درحالیکه بهسوی آیندهای بیگذرواژه حرکت میکنیم، گذرواژهها همچنان در کنار گذرکلیدها دردسترس خواهند بود"</string> <string name="choose_provider_title" msgid="8870795677024868108">"جایی را برای ذخیره کردن <xliff:g id="CREATETYPES">%1$s</xliff:g> انتخاب کنید"</string> - <string name="choose_provider_body" msgid="4967074531845147434">"مدیر گذرواژهای انتخاب کنید تا اطلاعاتتان ذخیره شود و دفعه بعدی سریعتر به سیستم وارد شوید"</string> + <string name="choose_provider_body" msgid="4967074531845147434">"مدیر گذرواژهای انتخاب کنید تا اطلاعاتتان را ذخیره کنید و دفعه بعد سریعتر به سیستم وارد شوید"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"برای <xliff:g id="APPNAME">%1$s</xliff:g> گذرکلید ایجاد شود؟"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"گذرواژه <xliff:g id="APPNAME">%1$s</xliff:g> ذخیره شود؟"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"اطلاعات ورود به سیستم <xliff:g id="APPNAME">%1$s</xliff:g> ذخیره شود؟"</string> @@ -49,9 +49,11 @@ <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"برگشتن به صفحه قبلی"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"بستن"</string> <string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"بستن"</string> - <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"گذرکلید ذخیرهشده برای <xliff:g id="APP_NAME">%1$s</xliff:g> استفاده شود؟"</string> + <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"از گذرکلید ذخیرهشده برای «<xliff:g id="APP_NAME">%1$s</xliff:g>» استفاده شود؟"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ورود به سیستم ذخیرهشده برای <xliff:g id="APP_NAME">%1$s</xliff:g> استفاده شود؟"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"انتخاب ورود به سیستم ذخیرهشده برای <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ورود به سیستم به روشی دیگر"</string> <string name="snackbar_action" msgid="37373514216505085">"مشاهده گزینهها"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ادامه"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"مدیریت ورود به سیستمها"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"از دستگاهی دیگر"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استفاده از دستگاه دیگری"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml index 11b4f59c6e77..04c7fe378cf2 100644 --- a/packages/CredentialManager/res/values-fi/strings.xml +++ b/packages/CredentialManager/res/values-fi/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Käytetäänkö tallennettua avainkoodiasi täällä: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Käytetäänkö tallennettuja kirjautumistietoja täällä: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Valitse tallennetut kirjautumistiedot (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Kirjaudu sisään toisella tavalla"</string> <string name="snackbar_action" msgid="37373514216505085">"Katseluasetukset"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Jatka"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Muuta kirjautumistietoja"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Toiselta laitteelta"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Käytä toista laitetta"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml index 605eed5687d1..8f39dd326872 100644 --- a/packages/CredentialManager/res/values-fr-rCA/strings.xml +++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml @@ -11,17 +11,17 @@ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Une sécurité accrue grâce aux clés d\'accès"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Avec les clés d\'accès, nul besoin de créer ou de mémoriser des mots de passe complexes"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Les clés d\'accès sont des clés numériques chiffrées que vous créez en utilisant votre empreinte digitale, votre visage ou le verrouillage de votre écran"</string> - <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Elles sont enregistrées dans un gestionnaire de mots de passe pour vous permettre de vous connecter sur d\'autres appareils"</string> + <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Elles sont enregistrées dans un gestionnaire de mots de passe pour vous permettre de vous connecter à d\'autres appareils"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"En savoir plus sur les clés d\'accès"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Technologie sans mot de passe"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Les clés d\'accès vous permettent de vous connecter sans utiliser de mots de passe. Il vous suffit d\'utiliser votre empreinte digitale, la reconnaissance faciale, un NIP ou un schéma de balayage pour vérifier votre identité et créer un mot de passe."</string> - <string name="public_key_cryptography_title" msgid="6751970819265298039">"Cryptographie des clés publiques"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Selon les normes de l\'Alliance FIDO (y compris Google, Apple, Microsoft et plus) et du W3C, les clés d\'accès utilisent des biclés cryptographiques. Contrairement au nom d\'utilisateur et à la chaîne de caractères que nous utilisons pour les mots de passe, une biclé privée-publique est créée pour une appli ou un site Web. La clé privée est stockée en toute sécurité sur votre appareil ou votre gestionnaire de mots de passe et confirme votre identité. La clé publique est partagée avec le serveur de l\'appli ou du site Web. Avec les clés correspondantes, vous pouvez vous inscrire et vous connecter instantanément."</string> + <string name="public_key_cryptography_title" msgid="6751970819265298039">"Cryptographie à clé publique"</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Selon les normes de l\'Alliance FIDO (y compris Google, Apple, Microsoft et plus) et du W3C, les clés d\'accès utilisent des biclés cryptographiques. Contrairement au nom d\'utilisateur et à la chaîne de caractères que nous utilisons pour les mots de passe, une biclé privée-publique est créée pour une application ou un site Web. La clé privée est stockée en toute sécurité sur votre appareil ou votre gestionnaire de mots de passe et confirme votre identité. La clé publique est partagée avec le serveur de l\'application ou du site Web. Avec les clés correspondantes, vous pouvez vous inscrire et vous connecter instantanément."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Sécurité accrue du compte"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Chaque clé est exclusivement liée à l\'application ou au site Web pour lequel elle a été créée, de sorte que vous ne pourrez jamais vous connecter par erreur à une application ou à un site Web frauduleux. En outre, comme les serveurs ne conservent que les clés publiques, le piratage informatique est beaucoup plus difficile."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Transition fluide"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"À mesure que nous nous dirigeons vers un avenir sans mots de passe, ceux-ci continueront d\'être utilisés parallèlement aux clés d\'accès"</string> - <string name="choose_provider_title" msgid="8870795677024868108">"Choisir où sauvegarder vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"À mesure que nous nous dirigeons vers un avenir sans mots de passe, ceux-ci continueront d\'être utilisés parallèlement aux clés d\'accès."</string> + <string name="choose_provider_title" msgid="8870795677024868108">"Choisir où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos renseignements et vous connecter plus rapidement la prochaine fois"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Créer une clé d\'accès pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"Enregistrer le mot de passe pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Utiliser votre connexion enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choisir une connexion enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Se connecter d\'une autre manière"</string> <string name="snackbar_action" msgid="37373514216505085">"Afficher les options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuer"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gérer les connexions"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"À partir d\'un autre appareil"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml index 3017e746b1c6..e0537c76247b 100644 --- a/packages/CredentialManager/res/values-fr/strings.xml +++ b/packages/CredentialManager/res/values-fr/strings.xml @@ -16,7 +16,7 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"Une technologie sans mot de passe"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Les clés d\'accès vous permettent de vous connecter sans dépendre d\'un mot de passe. Il vous suffit d\'utiliser votre empreinte digitale, la reconnaissance faciale, un code ou un schéma afin de vérifier votre identité et de créer une clé d\'accès."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Cryptographie à clé publique"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Les clés d\'accès, basées sur standards W3C et FIDO Alliance (Google, Apple, Microsoft, etc.), utilisent paires de clés cryptographiques. Une paire est créée pour appli ou site, contrairement au nom d\'utilisateur et au mot de passe. La clé privée, stockée en sécurité sur votre appareil ou sur un gestionnaire de mots de passe, confirme votre identité. La clé publique est partagée avec le serveur de l\'appli ou du site. Avec des clés correspondantes, l\'inscription et la connexion sont instantanées."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Les clés d\'accès, basées sur des standards W3C et FIDO Alliance (Google, Apple, Microsoft, etc.), utilisent des paires de clés cryptographiques. À la différence d\'un nom d\'utilisateur/mot de passe, une paire est créée pour chaque appli ou site. La clé privée, stockée en sécurité sur votre appareil ou dans un gestionnaire de mots de passe, confirme votre identité. La clé publique est partagée avec le serveur de l\'appli ou du site. Si les clés correspondent, l\'inscription et la connexion sont instantanées."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Des comptes plus sécurisés"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Chaque clé est liée exclusivement à l\'appli ou au site Web pour lequel elle a été créée, pour que vous ne puissiez jamais vous connecter par erreur à une appli ou un site Web frauduleux. De plus, le piratage est bien plus difficile, car les serveurs ne conservent que les clés publiques."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Une transition fluide"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Utiliser vos informations de connexion enregistrées pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choisir des informations de connexion enregistrées pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Se connecter d\'une autre manière"</string> <string name="snackbar_action" msgid="37373514216505085">"Voir les options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuer"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gérer les connexions"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Depuis un autre appareil"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml index ccb0e3bca93a..f7da57e4dc10 100644 --- a/packages/CredentialManager/res/values-gl/strings.xml +++ b/packages/CredentialManager/res/values-gl/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Queres usar a clave de acceso gardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Queres usar o método de inicio de sesión gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolle un método de inicio de sesión gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Iniciar sesión doutra forma"</string> <string name="snackbar_action" msgid="37373514216505085">"Ver opcións"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Xestionar os métodos de inicio de sesión"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Doutro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar outro dispositivo"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml index ed34209ba3cc..234742e99c17 100644 --- a/packages/CredentialManager/res/values-gu/strings.xml +++ b/packages/CredentialManager/res/values-gu/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે શું તમારી સાચવેલી પાસકીનો ઉપયોગ કરીએ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે શું તમારા સાચવેલા સાઇન-ઇનનો ઉપયોગ કરીએ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે કોઈ સાચવેલું સાઇન-ઇન પસંદ કરો"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"કોઈ અન્ય રીતે સાઇન ઇન કરો"</string> <string name="snackbar_action" msgid="37373514216505085">"વ્યૂના વિકલ્પો"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ચાલુ રાખો"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"સાઇન-ઇન મેનેજ કરો"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"કોઈ અન્ય ડિવાઇસમાંથી"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml index 029eeee92a25..7e00a8c31a44 100644 --- a/packages/CredentialManager/res/values-hi/strings.xml +++ b/packages/CredentialManager/res/values-hi/strings.xml @@ -8,8 +8,8 @@ <string name="string_learn_more" msgid="4541600451688392447">"ज़्यादा जानें"</string> <string name="content_description_show_password" msgid="3283502010388521607">"पासवर्ड दिखाएं"</string> <string name="content_description_hide_password" msgid="6841375971631767996">"पासवर्ड छिपाएं"</string> - <string name="passkey_creation_intro_title" msgid="4251037543787718844">"पासकी के साथ सुरक्षित रहें"</string> - <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"पासकी होने पर, आपको जटिल पासवर्ड बनाने या याद रखने की ज़रूरत नहीं पड़ती"</string> + <string name="passkey_creation_intro_title" msgid="4251037543787718844">"पासकी से पाएं ज़्यादा सुरक्षा"</string> + <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"पासकी होने पर, आपको मुश्किल पासवर्ड बनाने या याद रखने की ज़रूरत नहीं पड़ती"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"पासकी, एन्क्रिप्ट (सुरक्षित) की गई \'डिजिटल की\' होती हैं. इन्हें फ़िंगरप्रिंट, चेहरे या स्क्रीन लॉक का इस्तेमाल करके बनाया जाता है"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"पासकी को पासवर्ड मैनेजर में सेव किया जाता है, ताकि इनका इस्तेमाल करके आप अन्य डिवाइसों में साइन इन कर सकें"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"पासकी के बारे में ज़्यादा जानकारी"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई पासकी का इस्तेमाल करना है?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई जानकारी का इस्तेमाल करना है?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई जानकारी में से चुनें"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"किसी दूसरे तरीके से साइन इन करें"</string> <string name="snackbar_action" msgid="37373514216505085">"विकल्प देखें"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"जारी रखें"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इन करने की सुविधा को मैनेज करें"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"किसी दूसरे डिवाइस से"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"दूसरे डिवाइस का इस्तेमाल करें"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> की ओर से अनुरोध रद्द किया गया"</string> </resources> diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml index b454c414c864..c7ca34ac85ae 100644 --- a/packages/CredentialManager/res/values-hr/strings.xml +++ b/packages/CredentialManager/res/values-hr/strings.xml @@ -18,7 +18,7 @@ <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kriptografija javnog ključa"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Na temelju organizacije FIDO Alliance (koja uključuje Google, Apple, Microsoft i mnoge druge) i standarda W3C pristupni ključevi koriste kriptografske ključeve. Za razliku od korisničkog imena i niza znakova za zaporke, privatno-javni ključ izrađen je za aplikaciju ili web-lokaciju. Privatni ključ pohranjen je na vašem uređaju ili upravitelju zaporki i potvrđuje vaš identitet. Javni se ključ dijeli s poslužiteljem aplikacije ili web-lokacije. Uz odgovarajuće ključeve možete se odmah registrirati i prijaviti."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Poboljšana sigurnost računa"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"Svaki ključ povezan isključivo s aplikacijom ili web-lokacijom za koju je izrađen, stoga se nikad ne možete pogreškom prijaviti u prijevarnu aplikaciju ili na web-lokaciju. Osim toga, kad je riječ o poslužiteljima na kojem se nalaze samo javni ključevi, hakiranje je mnogo teže."</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"Svaki je ključ povezan isključivo s aplikacijom ili web-lokacijom za koju je izrađen, stoga se nikad ne možete pogreškom prijaviti u prijevarnu aplikaciju ili na web-lokaciju. Osim toga, kad je riječ o poslužiteljima na kojem se nalaze samo javni ključevi, hakiranje je mnogo teže."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Besprijekorni prijelaz"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"Kako idemo u smjeru budućnosti bez zaporki, one će i dalje biti dostupne uz pristupne ključeve"</string> <string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gdje će se spremati <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite li upotrijebiti spremljeni pristupni ključ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite li upotrijebiti spremljene podatke za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Odaberite spremljene podatke za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijavite se na neki drugi način"</string> <string name="snackbar_action" msgid="37373514216505085">"Prikaži opcije"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Nastavi"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljanje prijavama"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na drugom uređaju"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml index df8210b51c42..c277f233583f 100644 --- a/packages/CredentialManager/res/values-hu/strings.xml +++ b/packages/CredentialManager/res/values-hu/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett azonosítókulcsot használni?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett bejelentkezési adatait használni?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Mentett bejelentkezési adatok választása a következő számára: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Bejelentkezés más módon"</string> <string name="snackbar_action" msgid="37373514216505085">"Lehetőségek megtekintése"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Folytatás"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Bejelentkezési adatok kezelése"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Másik eszközről"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Másik eszköz használata"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml index 66d4339dedd5..9a4e9180619f 100644 --- a/packages/CredentialManager/res/values-hy/strings.xml +++ b/packages/CredentialManager/res/values-hy/strings.xml @@ -12,7 +12,7 @@ <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Անցաբառերի շնորհիվ դուք բարդ գաղտնաբառեր ստեղծելու կամ հիշելու անհրաժեշտություն չեք ունենա"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Անցաբառերը գաղտնագրված թվային բանալիներ են, որոնք ստեղծվում են մատնահետքի, դեմքով ապակողպման կամ էկրանի կողպման օգտագործմամբ"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Դուք կարող եք մուտք գործել այլ սարքերում, քանի որ անցաբառերը պահվում են գաղտնաբառերի կառավարիչում"</string> - <string name="more_about_passkeys_title" msgid="7797903098728837795">"Մանրամասն անցաբառերի մասին"</string> + <string name="more_about_passkeys_title" msgid="7797903098728837795">"Ավելին՝ անցաբառերի մասին"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Գաղտնաբառեր չպահանջող տեխնոլոգիա"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Անցաբառերը ձեզ թույլ են տալիս մուտք գործել առանց գաղտնաբառերի։ Ձեզ պարզապես հարկավոր է օգտագործել ձեր մատնահետքը, դիմաճանաչումը, PIN կոդը կամ նախշը՝ ձեր ինքնությունը հաստատելու և անցաբառ ստեղծելու համար։"</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Բաց բանալու կրիպտոգրաֆիա"</string> @@ -23,7 +23,7 @@ <string name="seamless_transition_detail" msgid="3440478759491650823">"Թեև մենք առանց գաղտնաբառերի ապագայի ճանապարհին ենք, դրանք դեռ հասանելի կլինեն անցաբառերի հետ մեկտեղ"</string> <string name="choose_provider_title" msgid="8870795677024868108">"Նշեք, թե որտեղ եք ուզում պահել ձեր <xliff:g id="CREATETYPES">%1$s</xliff:g>ը"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Ընտրեք գաղտնաբառերի կառավարիչ՝ ձեր տեղեկությունները պահելու և հաջորդ անգամ ավելի արագ մուտք գործելու համար"</string> - <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Ստեղծե՞լ անցաբառ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի համար"</string> + <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Ստեղծե՞լ անցաբառ <xliff:g id="APPNAME">%1$s</xliff:g> հավելվածի համար"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"Պահե՞լ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի գաղտնաբառը"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Պահե՞լ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի մուտքի տվյալները"</string> <string name="passkey" msgid="632353688396759522">"անցաբառ"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Օգտագործե՞լ պահված անցաբառը <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Օգտագործե՞լ մուտքի պահված տվյալները <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Ընտրեք մուտքի պահված տվյալներ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Մուտք գործել այլ եղանակով"</string> <string name="snackbar_action" msgid="37373514216505085">"Դիտել տարբերակները"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Շարունակել"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Մուտքի կառավարում"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Մեկ այլ սարքից"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Օգտագործել այլ սարք"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml index cd2e49fab8b5..c77cf4907a43 100644 --- a/packages/CredentialManager/res/values-in/strings.xml +++ b/packages/CredentialManager/res/values-in/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci sandi tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gunakan info login tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pilih info login tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Login dengan cara lain"</string> <string name="snackbar_action" msgid="37373514216505085">"Lihat opsi"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Lanjutkan"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kelola login"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Dari perangkat lain"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan perangkat lain"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml index 3bcf65933185..375a1c544f86 100644 --- a/packages/CredentialManager/res/values-is/strings.xml +++ b/packages/CredentialManager/res/values-is/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Nota vistaðan aðgangslykil fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Nota vistaða innskráningu fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Veldu vistaða innskráningu fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Skrá inn með öðrum hætti"</string> <string name="snackbar_action" msgid="37373514216505085">"Skoða valkosti"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Áfram"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Stjórna innskráningu"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Úr öðru tæki"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Nota annað tæki"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml index 97de0fb23610..49eb54704cd2 100644 --- a/packages/CredentialManager/res/values-it/strings.xml +++ b/packages/CredentialManager/res/values-it/strings.xml @@ -20,7 +20,7 @@ <string name="improved_account_security_title" msgid="1069841917893513424">"Account ancora più sicuri"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Ogni chiave è collegata in modo esclusivo all\'app o al sito web per cui è stata creata, quindi non puoi mai accedere a un\'app o un sito web fraudolenti per sbaglio. Inoltre, le compromissioni diventano molto più difficili perché i server conservano soltanto le chiavi pubbliche."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Transizione graduale"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Mentre ci dirigiamo verso un futuro senza password, queste ultime saranno ancora disponibili insieme alle passkey"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Mentre ci dirigiamo verso un futuro senza password, queste ultime saranno ancora disponibili insieme alle passkey."</string> <string name="choose_provider_title" msgid="8870795677024868108">"Scegli dove salvare le <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Seleziona un gestore delle password per salvare i tuoi dati e accedere più velocemente la prossima volta"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vuoi creare una passkey per <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vuoi usare la passkey salvata per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vuoi usare l\'accesso salvato per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Scegli un accesso salvato per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Accedi in un altro modo"</string> <string name="snackbar_action" msgid="37373514216505085">"Visualizza opzioni"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continua"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestisci gli accessi"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Da un altro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usa un dispositivo diverso"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml index f4b1906c8e94..d87c4f424530 100644 --- a/packages/CredentialManager/res/values-iw/strings.xml +++ b/packages/CredentialManager/res/values-iw/strings.xml @@ -16,7 +16,7 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"טכנולוגיה ללא סיסמאות"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"מפתחות גישה מאפשרים לך להיכנס לחשבון בלי להסתמך על סיסמאות. עליך רק להשתמש בטביעת אצבע, בזיהוי הפנים, בקוד אימות או בקו ביטול נעילה כדי לאמת את זהותך וליצור מפתח גישה."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"קריפטוגרפיה של מפתח ציבורי"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"על סמך תקן FIDO (ארגון שכולל חברות כמו Google, Apple, Microsoft ועוד) ותקני W3C, מפתחות הגישה מבוססים על זוגות של מפתחות קריפטוגרפיים. בניגוד למחרוזות תווים ולשם המשתמש שבהם אנחנו משתמשים בסיסמאות, זוג מפתחות – מפתח פרטי ומפתח ציבורי – נוצר עבור אפליקציה או אתר. המפתח הפרטי מאוחסן בבטחה במכשיר או במנהל הסיסמאות שלך, ומאמת את זהותך. המפתח הציבורי משותף עם השרת של האפליקציה או האתר. בעזרת המפתחות התואמים אפשר מיד להירשם ולהיכנס לחשבון."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"על סמך תקן FIDO (ארגון שכולל חברות כמו Google, Apple, Microsoft ועוד) ותקני W3C, מפתחות הגישה מבוססים על זוגות של מפתחות קריפטוגרפיים. בניגוד לשם המשתמש ולמחרוזת התווים ששמשמשת אצלנו בתור סיסמה, בתקן הזה נוצר זוג מפתחות – מפתח פרטי ומפתח ציבורי – עבור אפליקציה או אתר. המפתח הפרטי מאוחסן בבטחה במכשיר או במנהל הסיסמאות שלך, ומאמת את זהותך. המפתח הציבורי משותף עם השרת של האפליקציה או האתר. בעזרת המפתחות התואמים אפשר מיד להירשם ולהיכנס לחשבון."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"אבטחה טובה יותר של החשבון"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"כל מפתח מקושר אך ורק לאפליקציה או לאתר שעבורם הוא נוצר, ולכן אף פעם אי אפשר להיכנס בטעות לחשבון באפליקציה או באתר שמטרתם להונות. בנוסף, כיוון שהשרתים שומרים רק מפתחות ציבוריים, קשה יותר לפרוץ לחשבון."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"מעבר חלק"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"להשתמש במפתח גישה שנשמר עבור <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"להשתמש בפרטי הכניסה שנשמרו עבור <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"בחירת פרטי כניסה שמורים עבור <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"כניסה בדרך אחרת"</string> <string name="snackbar_action" msgid="37373514216505085">"הצגת האפשרויות"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"המשך"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ניהול כניסות"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ממכשיר אחר"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"צריך להשתמש במכשיר אחר"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml index 35d011c09700..2bb7e9ca461a 100644 --- a/packages/CredentialManager/res/values-ja/strings.xml +++ b/packages/CredentialManager/res/values-ja/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したパスキーを使用しますか?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したログイン情報を使用しますか?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したログイン情報の選択"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"別の方法でログイン"</string> <string name="snackbar_action" msgid="37373514216505085">"オプションを表示"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"続行"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ログインを管理"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"別のデバイスを使う"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"別のデバイスを使用"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> がリクエストをキャンセルしました"</string> </resources> diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml index 545106b7df99..0f638ef5d7b8 100644 --- a/packages/CredentialManager/res/values-ka/strings.xml +++ b/packages/CredentialManager/res/values-ka/strings.xml @@ -16,11 +16,11 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"უპაროლო ტექნოლოგია"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"წვდომის გასაღებები საშუალებას გაძლევთ, სისტემაში შეხვიდეთ პაროლის გარეშე. უბრალოდ, ვინაობის დასადასტურებლად და წვდომის გასაღების შესაქმნელად უნდა გამოიყენოთ თითის ანაბეჭდი, სახით ამოცნობა, PIN-კოდი, ან განბლოკვის გრაფიკული გასაღები."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"საჯარო გასაღების კრიპტოგრაფია"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO-ს ალიანსისა (Google, Apple, Microsoft და ა.შ.) და W3C-ის სტანდარტების შესაბამისად, წვდომის გასაღებები იყენებს კრიპტოგრაფიულ გასაღებების წყვილს. მომხ. სახ. და სიმბ. სტრიქ. განსხვავებით, რომელთაც პაროლ. ვიყენებთ, რამდენიმე პირადი/საჯარო გას. იქმნება აპის ან ვებსაიტისთვის. პირადი გასაღები უსაფრთხოდ ინახება მოწყობილობაზე ან პაროლ. მმართველში და ის ადასტურებს თქვენს ვინაობას. საჯარო გას. ზიარდება აპისა და ვებ. სერვერის მეშვეობით. შესაბ. გასაღებებით შეგიძლიათ მაშინვე დარეგისტ. და სისტ. შეხვიდეთ."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO ალიანსის (Google, Apple, Microsoft და სხვა) და W3C სტანდარტების შესაბამისად, წვდომის გასაღებები კრიპტოგრაფიულ გასაღებთა წყვილია. პაროლზე გამოყენებული მომხმარებლის სახელის/სიმბოლოთა სტრიქონების განსხვავებით, პირადი/საჯარო გასაღები იქმნება აპისა და ვებსაიტისთვის. პირადი გასაღები უსაფრთხოდ ინახება მოწყობილობაზე/პაროლთა მმართველში და ადასტურებს ვინაობას. საჯარო გასაღები კი ზიარდება აპთან/ვებსერვერთან. შესაბაბისი გასაღებებით შეგიძლიათ დაუყოვნებლივ დარეგისტრირდეთ და სისტემაში შეხვიდეთ."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"ანგარიშის გაუმჯობესებული უსაფრთხოება"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"თითოეული გასაღები დაკავშირებულია მხოლოდ აპთან ან ვებსაიტთან, რომელთათვისაც ის შეიქმნა, ამიტომაც შემთხვევით ვერასდროს შეხვალთ თაღლითურ აპში თუ ვებსაიტზე. ამასთანავე, სერვერები ინახავს მხოლოდ საჯარო გასაღებებს, რაც ართულებს გატეხვის ალბათობას."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"დაუბრკოლებელი გადასვლა"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"უპაროლო მომავალში პაროლები კვლავ ხელმისაწვდომი იქნება, წვდომის გასაღებებთან ერთად"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"უპაროლო მომავალში გადასვლის პროცესის პარალელურად პაროლები კვლავ ხელმისაწვდომი იქნება, წვდომის გასაღებებთან ერთად"</string> <string name="choose_provider_title" msgid="8870795677024868108">"აირჩიეთ სად შეინახოთ თქვენი <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"აირჩიეთ პაროლების მმართველი თქვენი ინფორმაციის შესანახად, რომ მომავალში უფრო სწრაფად შეხვიდეთ."</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"შექმნით წვდომის გასაღებს <xliff:g id="APPNAME">%1$s</xliff:g> აპისთვის?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"გსურთ თქვენი დამახსოვრებული წვდომის გასაღების გამოყენება აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"გსურთ თქვენი დამახსოვრებული სისტემაში შესვლის მონაცემების გამოყენება აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"აირჩიეთ სისტემაში შესვლის ინფორმაცია აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"სხვა ხერხით შესვლა"</string> <string name="snackbar_action" msgid="37373514216505085">"პარამეტრების ნახვა"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"გაგრძელება"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"სისტემაში შესვლის მონაცემების მართვა"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"სხვა მოწყობილობიდან"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"გამოიყენეთ სხვა მოწყობილობა"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"თხოვნა გაუქმებულია <xliff:g id="APP_NAME">%1$s</xliff:g>-ის მიერ"</string> </resources> diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml index a4f3dc35116a..a4703e827242 100644 --- a/packages/CredentialManager/res/values-kk/strings.xml +++ b/packages/CredentialManager/res/values-kk/strings.xml @@ -16,7 +16,7 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"Құпия сөзсіз технология"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Кіру кілттері сізге құпия сөзге сүйенбей-ақ кіруге мүмкіндік береді. Жеке басыңызды растап, кіру кілтін жасау үшін тек саусақ ізі, бет тану функциясы, PIN коды немесе сырғыту өрнегі қажет."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Ашық кілт криптографиясы"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Alliance (оған Google, Apple, Microsoft, т.б. кіреді) және W3C стандарттары бойынша кіру кілттерінде криптографиялық кілт жұптары қолданылады. Құпия сөз үшін пайдаланушы аты мен таңбалар қолданылады, ал қолданба немесе веб-сайт үшін жеке-ашық кілт жұбы жасалады. Жеке кілт құрылғыңызда немесе құпия сөз менеджерінде қорғалып, сақталады. Ол жеке басыңызды растау үшін қажет. Ашық кілт қолданба немесе веб-сайт серверіне жіберіледі. Кілттер сәйкес келсе, бірден тіркеліп, аккаунтқа кіре аласыз."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Alliance (оған Google, Apple, Microsoft, т.б. кіреді) және W3C стандарттары бойынша кіру кілттерінде криптографиялық кілт жұптары қолданылады. Құпия сөз үшін пайдаланушы аты мен таңбалар қолданылады, ал қолданба немесе веб-сайт үшін жеке-ашық кілт жұбы жасалады. Жеке кілт құрылғыңызда немесе құпия сөз менеджерінде қауіпсіз сақталады. Ол жеке басыңызды растау үшін қажет. Ашық кілт қолданба немесе веб-сайт серверіне жіберіледі. Кілттер сәйкес келсе, бірден тіркеліп, аккаунтқа кіре аласыз."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Аккаунттың қосымша қауіпсіздігі"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Әрбір кілт өзі арнайы жасалған қолданбамен немесе веб-сайтпен ғана байланысты болады, сондықтан алаяқтар қолданбасына немесе веб-сайтына байқаусызда кіру мүмкін емес. Онымен қоса тек ашық кілттер сақталатын серверлер арқасында хакерлердің бұзып кіруі айтарлықтай қиындады."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Оңай ауысу"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған кіру кілті пайдаланылсын ба?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған тіркелу деректері пайдаланылсын ба?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған тіркелу деректерін таңдаңыз"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Басқаша кіру"</string> <string name="snackbar_action" msgid="37373514216505085">"Опцияларды көру"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Жалғастыру"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кіру әрекеттерін басқару"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Басқа құрылғыдан жасау"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Басқа құрылғыны пайдалану"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml index 1e7b4e6d4844..97067c5f7e33 100644 --- a/packages/CredentialManager/res/values-km/strings.xml +++ b/packages/CredentialManager/res/values-km/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ប្រើកូដសម្ងាត់ដែលបានរក្សាទុករបស់អ្នកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ប្រើការចូលគណនីដែលបានរក្សាទុករបស់អ្នកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"ជ្រើសរើសការចូលគណនីដែលបានរក្សាទុកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ចូលគណនីដោយប្រើវិធីផ្សេងទៀត"</string> <string name="snackbar_action" msgid="37373514216505085">"មើលជម្រើស"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"បន្ត"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"គ្រប់គ្រងការចូលគណនី"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ពីឧបករណ៍ផ្សេងទៀត"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ប្រើឧបករណ៍ផ្សេង"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"បានបោះបង់សំណើដោយ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml index 561348edd523..ae6c8efa738f 100644 --- a/packages/CredentialManager/res/values-kn/strings.xml +++ b/packages/CredentialManager/res/values-kn/strings.xml @@ -11,14 +11,14 @@ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"ಪಾಸ್ಕೀಗಳ ಸಹಾಯದಿಂದ ಸುರಕ್ಷಿತವಾಗಿರಿ"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"ಪಾಸ್ಕೀಗಳ ಮೂಲಕ, ನೀವು ಕ್ಲಿಷ್ಟ ಪಾಸ್ವರ್ಡ್ಗಳನ್ನು ರಚಿಸುವ ಅಥವಾ ನೆನಪಿಟ್ಟುಕೊಳ್ಳುವ ಅಗತ್ಯವಿಲ್ಲ"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ಪಾಸ್ಕೀಗಳು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್, ಫೇಸ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ನೀವು ರಚಿಸುವ ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ ಡಿಜಿಟಲ್ ಕೀಗಳಾಗಿವೆ"</string> - <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ಅವುಗಳನ್ನು ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ ಉಳಿಸಲಾಗಿದೆ, ಹಾಗಾಗಿ ನೀವು ಇತರ ಸಾಧನಗಳಲ್ಲಿ ಸೈನ್ ಇನ್ ಮಾಡಬಹುದು"</string> + <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ಅವುಗಳನ್ನು ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ ಉಳಿಸಲಾಗುತ್ತದೆ, ಹಾಗಾಗಿ ನೀವು ಇತರ ಸಾಧನಗಳಲ್ಲಿ ಸೈನ್ ಇನ್ ಮಾಡಬಹುದು"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"ಪಾಸ್ಕೀಗಳ ಕುರಿತು ಇನ್ನಷ್ಟು"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"ಪಾಸ್ವರ್ಡ್ ರಹಿತ ತಂತ್ರಜ್ಞಾನ"</string> - <string name="passwordless_technology_detail" msgid="6853928846532955882">"ಪಾಸ್ಕೀಗಳು ಪಾಸ್ವರ್ಡ್ಗಳನ್ನು ಅವಲಂಬಿಸದೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಅನುಮತಿಸುತ್ತದೆ. ನಿಮ್ಮ ಗುರುತನ್ನು ಪರಿಶೀಲಿಸಲು ಮತ್ತು ಪಾಸ್ಕೀ ರಚಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್, ಮುಖ ಗುರುತಿಸುವಿಕೆ, ಪಿನ್ ಅಥವಾ ಸ್ವೈಪ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು ಬಳಸಬೇಕಾಗುತ್ತದೆ."</string> + <string name="passwordless_technology_detail" msgid="6853928846532955882">"ಪಾಸ್ಕೀಗಳು ಪಾಸ್ವರ್ಡ್ಗಳನ್ನು ಅವಲಂಬಿಸದೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಅನುಮತಿಸುತ್ತವೆ. ನಿಮ್ಮ ಗುರುತನ್ನು ದೃಢೀಕರಿಸಲು ಮತ್ತು ಪಾಸ್ಕೀ ರಚಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್, ಮುಖ ಗುರುತಿಸುವಿಕೆ, ಪಿನ್ ಅಥವಾ ಸ್ವೈಪ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು ಬಳಸಬೇಕಾಗುತ್ತದೆ."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"ಸಾರ್ವಜನಿಕ ಕೀ ಕ್ರಿಪ್ಟೋಗ್ರಫಿ"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO ಅಲೈಯನ್ಸ್ (ಇದು Google, Apple, Microsoft ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ) ಮತ್ತು W3C ಮಾನದಂಡಗಳನ್ನು ಆಧರಿಸಿ, ಪಾಸ್ಕೀಗಳು ಕ್ರಿಪ್ಟೋಗ್ರಾಫಿಕ್ ಕೀ ಜೋಡಿಗಳನ್ನು ಬಳಸುತ್ತವೆ. ಪಾಸ್ವರ್ಡ್ಗಳಿಗಾಗಿ ನಾವು ಬಳಸುವ ಬಳಕೆದಾರಹೆಸರು ಮತ್ತು ಅಕ್ಷರಗಳ ಸ್ಟ್ರಿಂಗ್ಗಿಂತ ಭಿನ್ನವಾಗಿ, ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ಗಾಗಿ ಖಾಸಗಿ-ಸಾರ್ವಜನಿಕ ಕೀ ಜೋಡಿಯನ್ನು ರಚಿಸಲಾಗಿದೆ. ಖಾಸಗಿ ಕೀ ಅನ್ನು ನಿಮ್ಮ ಸಾಧನ ಅಥವಾ ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ ಸುರಕ್ಷಿತವಾಗಿ ಸಂಗ್ರಹಿಸಲಾಗಿದೆ ಮತ್ತು ಅದು ನಿಮ್ಮ ಗುರುತನ್ನು ಖಚಿತಪಡಿಸುತ್ತದೆ. ಸಾರ್ವಜನಿಕ ಕೀ ಅನ್ನು ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ ಸರ್ವರ್ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗಿದೆ. ಅನುಗುಣವಾದ ಕೀ ಮೂಲಕ, ನೀವು ತಕ್ಷಣ ನೋಂದಾಯಿಸಬಹುದು ಮತ್ತು ಸೈನ್ ಇನ್ ಮಾಡಬಹುದು."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO ಅಲೈಯನ್ಸ್ (ಇದು Google, Apple, Microsoft ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಒಳಗೊಂಡಿದೆ) ಮತ್ತು W3C ಮಾನದಂಡಗಳನ್ನು ಆಧರಿಸಿ, ಪಾಸ್ಕೀಗಳು ಕ್ರಿಪ್ಟೋಗ್ರಾಫಿಕ್ ಕೀ ಜೋಡಿಗಳನ್ನು ಬಳಸುತ್ತವೆ. ಪಾಸ್ವರ್ಡ್ಗಳಿಗಾಗಿ ನಾವು ಬಳಸುವ ಬಳಕೆದಾರರ ಹೆಸರು ಮತ್ತು ಅಕ್ಷರಗಳ ಸ್ಟ್ರಿಂಗ್ಗಿಂತ ಭಿನ್ನವಾಗಿ, ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ಗಾಗಿ ಖಾಸಗಿ-ಸಾರ್ವಜನಿಕ ಕೀ ಜೋಡಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತದೆ. ಖಾಸಗಿ ಕೀ ಅನ್ನು ನಿಮ್ಮ ಸಾಧನ ಅಥವಾ ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ ಸುರಕ್ಷಿತವಾಗಿ ಸಂಗ್ರಹಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ಅದು ನಿಮ್ಮ ಗುರುತನ್ನು ಖಚಿತಪಡಿಸುತ್ತದೆ. ಸಾರ್ವಜನಿಕ ಕೀ ಅನ್ನು ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ ಸರ್ವರ್ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತದೆ. ಅನುಗುಣವಾದ ಕೀಗಳೊಂದಿಗೆ, ನೀವು ತಕ್ಷಣ ನೋಂದಾಯಿಸಬಹುದು ಮತ್ತು ಸೈನ್ ಇನ್ ಮಾಡಬಹುದು."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"ಸುಧಾರಿತ ಖಾತೆಯ ಭದ್ರತೆ"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"ಪ್ರತಿಯೊಂದು ಕೀ ಅವುಗಳನ್ನು ರಚಿಸಲಾದ ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ನ ಜೊತೆಗೆ ಪ್ರತ್ಯೇಕವಾಗಿ ಲಿಂಕ್ ಮಾಡಲಾಗಿದೆ, ಆದ್ದರಿಂದ ನೀವು ಎಂದಿಗೂ ತಪ್ಪಾಗಿ ವಂಚನೆಯ ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಜೊತೆಗೆ, ಸರ್ವರ್ಗಳು ಮಾತ್ರ ಸಾರ್ವಜನಿಕ ಕೀಗಳನ್ನು ಇಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ, ಹ್ಯಾಕಿಂಗ್ ಮಾಡುವುದು ತುಂಬಾ ಕಷ್ಟಕರವಾಗಿದೆ."</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"ಪ್ರತಿಯೊಂದು ಕೀಯನ್ನು ಯಾವ ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ಗಾಗಿ ರಚಿಸಲಾಗಿದೆಯೋ ಅದರೊಂದಿಗೆ ಮಾತ್ರ ಲಿಂಕ್ ಮಾಡಲಾಗುತ್ತದೆ. ಆದ್ದರಿಂದ ನೀವು ಎಂದಿಗೂ ತಪ್ಪಾಗಿ ವಂಚನೆಯ ಆ್ಯಪ್ ಅಥವಾ ವೆಬ್ಸೈಟ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಜೊತೆಗೆ, ಸರ್ವರ್ಗಳು ಸಾರ್ವಜನಿಕ ಕೀಗಳನ್ನು ಮಾತ್ರ ಇಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ, ಹ್ಯಾಕಿಂಗ್ ಮಾಡುವುದು ತುಂಬಾ ಕಷ್ಟಕರವಾಗಿದೆ."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"ಅಡಚಣೆರಹಿತ ಪರಿವರ್ತನೆ"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"ನಾವು ಪಾಸ್ವರ್ಡ್ ರಹಿತ ಭವಿಷ್ಯದತ್ತ ಸಾಗುತ್ತಿರುವಾಗ, ಪಾಸ್ಕೀಗಳ ಜೊತೆಗೆ ಪಾಸ್ವರ್ಡ್ಗಳು ಇನ್ನೂ ಲಭ್ಯವಿರುತ್ತವೆ"</string> <string name="choose_provider_title" msgid="8870795677024868108">"ನಿಮ್ಮ <xliff:g id="CREATETYPES">%1$s</xliff:g> ಅನ್ನು ಎಲ್ಲಿ ಉಳಿಸಬೇಕು ಎಂದು ಆರಿಸಿ"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ನಿಮ್ಮ ಪಾಸ್ಕೀ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ನಿಮ್ಮ ಸೈನ್-ಇನ್ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ಸೈನ್-ಇನ್ ಮಾಹಿತಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ಬೇರೆ ವಿಧಾನದಲ್ಲಿ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string> <string name="snackbar_action" msgid="37373514216505085">"ಆಯ್ಕೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ಮುಂದುವರಿಸಿ"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ಸೈನ್-ಇನ್ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ಮತ್ತೊಂದು ಸಾಧನದಿಂದ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ಬೇರೆ ಸಾಧನವನ್ನು ಬಳಸಿ"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml index 502d9eeb8c5a..4834eaf9e223 100644 --- a/packages/CredentialManager/res/values-ko/strings.xml +++ b/packages/CredentialManager/res/values-ko/strings.xml @@ -13,7 +13,7 @@ <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"패스키는 지문, 얼굴 또는 화면 잠금으로 생성하는 암호화된 디지털 키입니다."</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"비밀번호 관리자에 저장되므로 다른 기기에서 로그인할 수 있습니다."</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"패스키 자세히 알아보기"</string> - <string name="passwordless_technology_title" msgid="2497513482056606668">"비밀번호 없는 기술"</string> + <string name="passwordless_technology_title" msgid="2497513482056606668">"패스워드리스 기술"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"패스키를 이용하면 비밀번호에 의존하지 않고 로그인할 수 있습니다. 지문, 얼굴 인식, PIN 또는 스와이프 패턴만으로 본인 인증을 하고 패스키를 만들 수 있습니다."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"공개 키 암호화"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO 연합(Google, Apple, Microsoft 등 포함) 및 W3C 표준을 토대로 패스키는 암호화 키 쌍을 사용합니다. 사용자 이름과 비밀번호로 사용하는 문자열과는 달리 비공개-공개 키 쌍은 특정 앱 또는 웹사이트를 대상으로 생성됩니다. 비공개 키는 안전하게 기기 또는 비밀번호 관리자에 저장되며 사용자 본인 인증에 사용됩니다. 공개 키는 앱 또는 웹사이트 서버와 공유됩니다. 해당하는 키를 사용하면 즉시 등록하고 로그인할 수 있습니다."</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용으로 저장된 패스키를 사용하시겠습니까?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용 저장된 로그인 정보를 사용하시겠습니까?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용 저장된 로그인 정보 선택"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"다른 방법으로 로그인"</string> <string name="snackbar_action" msgid="37373514216505085">"옵션 보기"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"계속"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"로그인 관리"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"다른 기기에서"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"다른 기기 사용"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml index 68f082b82452..afbac7954005 100644 --- a/packages/CredentialManager/res/values-ky/strings.xml +++ b/packages/CredentialManager/res/values-ky/strings.xml @@ -8,19 +8,19 @@ <string name="string_learn_more" msgid="4541600451688392447">"Кеңири маалымат"</string> <string name="content_description_show_password" msgid="3283502010388521607">"Сырсөздү көрсөтүү"</string> <string name="content_description_hide_password" msgid="6841375971631767996">"Сырсөздү жашыруу"</string> - <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Мүмкүндүк алуу ачкычтары менен коопсузураак болот"</string> - <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Мүмкүндүк алуу ачкычтары менен татаал сырсөздөрдү түзүп же эстеп калуунун кереги жок"</string> - <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Мүмкүндүк алуу ачкычтары – манжаңыздын изи, жүзүңүз же экранды кулпулоо функциясы аркылуу түзгөн шифрленген санариптик ачкычтар"</string> + <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Киргизүүчү ачкычтар менен коопсузураак болот"</string> + <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Киргизүүчү ачкычтар менен татаал сырсөздөрдү түзүп же эстеп калуунун кереги жок"</string> + <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Киргизүүчү ачкычтар – манжаңыздын изи, жүзүңүз же экранды кулпулоо функциясы аркылуу түзгөн шифрленген санариптик ачкычтар"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Алар сырсөздөрдү башкаргычка сакталып, аккаунтуңузга башка түзмөктөрдөн кире аласыз"</string> - <string name="more_about_passkeys_title" msgid="7797903098728837795">"Мүмкүндүк алуу ачкычтары тууралуу кеңири маалымат"</string> + <string name="more_about_passkeys_title" msgid="7797903098728837795">"Киргизүүчү ачкычтар тууралуу кеңири маалымат"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Сырсөзсүз технология"</string> - <string name="passwordless_technology_detail" msgid="6853928846532955882">"Мүмкүндүк алуу ачкычтары аркылуу сырсөздөрсүз эле аккаунтуңузга кире аласыз. Ким экениңизди ырастоо жана мүмкүндүк алуу ачкычын түзүү үчүн жөн гана манжаңыздын изин, жүзүнөн таануу функциясын, PIN кодду же графикалык ачкычты колдонушуңуз керек болот."</string> + <string name="passwordless_technology_detail" msgid="6853928846532955882">"Киргизүүчү ачкычтар аркылуу сырсөздөрсүз эле аккаунтуңузга кире аласыз. Ким экениңизди ырастоо жана киргизүүчү ачкычты түзүү үчүн жөн гана манжаңыздын изин, жүзүнөн таануу функциясын, PIN кодду же графикалык ачкычты колдонушуңуз керек болот."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Жалпыга ачык ачкыч менен криптография"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Alliance (Google, Apple, Microsoft ж.б.) жана W3C стандартына ылайык, мүмкүндүк алуу ачкычтары криптографиялык жуп ачкычтарды колдонот. Колдонмо же вебсайтта колдонуучунун аты жана сырсөз үчүн колдонулган символ сабы эмес, купуя жана жалпыга ачык жуп ачкыч түзүлөт. Купуя ачкыч түзмөктө же сырсөздөрдү башкаргычта коопсуз сакталып, өздүгүңүздү ырастоо үчүн колдонулат. Жалпыга ачык ачкыч колдонмо же вебсайттын серверине жөнөтүлөт. Туура келген ачкычтар аркылуу тез катталып жана кире аласыз."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Alliance (Google, Apple, Microsoft ж.б.) жана W3C стандартына ылайык, киргизүүчү ачкычтар криптографиялык жуп ачкычтарды колдонот. Колдонмо же вебсайтта колдонуучунун аты жана сырсөз үчүн колдонулган символ сабы эмес, купуя жана жалпыга ачык жуп ачкыч түзүлөт. Купуя ачкыч түзмөктө же сырсөздөрдү башкаргычта коопсуз сакталып, өздүгүңүздү ырастоо үчүн колдонулат. Жалпыга ачык ачкыч колдонмо же вебсайттын серверине жөнөтүлөт. Туура келген ачкычтар аркылуу тез катталып жана кире аласыз."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Аккаунттун коопсуздугу жакшыртылды"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Ар бир ачкыч өзү арналган колдонмо же вебсайт менен гана байланыштырылгандыктан, эч качан шылуундардын колдонмолоруна же вебсайттарына жаңылыштык менен кирип албайсыз. Мындан тышкары, серверлерде жалпыга ачык ачкычтар гана сакталгандыктан, хакерлик кылуу кыйла кыйын."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Тез которулуу"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Сырсөзсүз келечекти көздөй баратсак да, аларды мүмкүндүк алуу ачкычтары менен бирге колдоно берүүгө болот"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Сырсөзсүз келечекти көздөй баратсак да, аларды киргизүүчү ачкычтар менен бирге колдоно берүүгө болот"</string> <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> кайда сакталарын тандаңыз"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Маалыматыңызды сактоо жана кийинки жолу тезирээк кирүү үчүн сырсөздөрдү башкаргычты тандаңыз"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> колдонмосуна киргизүүчү ачкыч түзөсүзбү?"</string> @@ -28,7 +28,7 @@ <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> үчүн кирүү маалыматы сакталсынбы?"</string> <string name="passkey" msgid="632353688396759522">"киргизүүчү ачкыч"</string> <string name="password" msgid="6738570945182936667">"сырсөз"</string> - <string name="passkeys" msgid="5733880786866559847">"мүмкүндүк алуу ачкычтары"</string> + <string name="passkeys" msgid="5733880786866559847">"киргизүүчү ачкычтар"</string> <string name="passwords" msgid="5419394230391253816">"сырсөздөр"</string> <string name="sign_ins" msgid="4710739369149469208">"кирүүлөр"</string> <string name="sign_in_info" msgid="2627704710674232328">"кирүү маалыматы"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна кирүү үчүн сакталган ачкычты колдоносузбу?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган кирүү параметрин колдоносузбу?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн кирүү маалыматын тандаңыз"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Башка жол менен кирүү"</string> <string name="snackbar_action" msgid="37373514216505085">"Параметрлерди көрүү"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Улантуу"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кирүү параметрлерин тескөө"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Башка түзмөктөн"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Башка түзмөктү колдонуу"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml index d7e4c31f8e8e..5c99c2516049 100644 --- a/packages/CredentialManager/res/values-lo/strings.xml +++ b/packages/CredentialManager/res/values-lo/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ໃຊ້ກະແຈຜ່ານທີ່ບັນທຶກໄວ້ຂອງທ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ໃຊ້ການເຂົ້າສູ່ລະບົບທີ່ບັນທຶກໄວ້ຂອງທ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"ເລືອກການເຂົ້າສູ່ລະບົບທີ່ບັນທຶກໄວ້ສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ເຂົ້າສູ່ລະບົບດ້ວຍວິທີອື່ນ"</string> <string name="snackbar_action" msgid="37373514216505085">"ເບິ່ງຕົວເລືອກ"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ສືບຕໍ່"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ຈັດການການເຂົ້າສູ່ລະບົບ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ຈາກອຸປະກອນອື່ນ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ໃຊ້ອຸປະກອນອື່ນ"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"ການຮ້ອງຂໍຖືກຍົກເລີກໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml index 33944c23228b..7dcd9d0b942c 100644 --- a/packages/CredentialManager/res/values-lt/strings.xml +++ b/packages/CredentialManager/res/values-lt/strings.xml @@ -20,7 +20,7 @@ <string name="improved_account_security_title" msgid="1069841917893513424">"Geresnė paskyros sauga"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Kiekvienas raktas išskirtinai susietas su programa ar svetaine, kuriai buvo sukurtas, todėl niekada per klaidą neprisijungsite prie apgavikiškos programos ar svetainės. Be to, viešieji raktai laikomi tik serveriuose, todėl įsilaužti tampa gerokai sudėtingiau."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Sklandus perėjimas"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Kol stengiamės padaryti, kad ateityje nereikėtų naudoti slaptažodžių, jie vis dar bus pasiekiami kartu su „passkey“"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Kol stengiamės padaryti, kad ateityje nereikėtų naudoti slaptažodžių, jie vis dar bus pasiekiami kartu su „passkey“."</string> <string name="choose_provider_title" msgid="8870795677024868108">"Pasirinkite, kur išsaugoti „<xliff:g id="CREATETYPES">%1$s</xliff:g>“"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Pasirinkite slaptažodžių tvarkyklę, kurią naudodami galėsite išsaugoti informaciją ir kitą kartą prisijungti greičiau"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Sukurti „passkey“, skirtą „<xliff:g id="APPNAME">%1$s</xliff:g>“?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Naudoti išsaugotą „passkey“ programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Naudoti išsaugotą prisijungimo informaciją programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pasirinkite išsaugotą prisijungimo informaciją programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prisijungti kitu būdu"</string> <string name="snackbar_action" msgid="37373514216505085">"Peržiūrėti parinktis"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Tęsti"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Tvarkyti prisijungimo informaciją"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Naudojant kitą įrenginį"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Naudoti kitą įrenginį"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml index 0aa4aa722c3a..d68124fa737d 100644 --- a/packages/CredentialManager/res/values-lv/strings.xml +++ b/packages/CredentialManager/res/values-lv/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vai izmantot saglabāto piekļuves atslēgu lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vai izmantot saglabāto pierakstīšanās informāciju lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Saglabātas pierakstīšanās informācijas izvēle lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Pierakstīties citā veidā"</string> <string name="snackbar_action" msgid="37373514216505085">"Skatīt opcijas"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Turpināt"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Pierakstīšanās informācijas pārvaldība"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"No citas ierīces"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Izmantot citu ierīci"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml index 3287246a560b..0249a8677d07 100644 --- a/packages/CredentialManager/res/values-mk/strings.xml +++ b/packages/CredentialManager/res/values-mk/strings.xml @@ -14,13 +14,13 @@ <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Се зачувуваат во управник со лозинки за да може да се најавувате на други уреди"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Повеќе за криптографските клучеви"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Технологија без лозинки"</string> - <string name="passwordless_technology_detail" msgid="6853928846532955882">"Криптографските клучеви дозволуваат да се најавувате без да се потпирате на лозинки. Треба само да користите отпечаток, препознавање лик, PIN или шема на повлекување за да го потврдите идентитетот и да создадете криптографски клуч."</string> + <string name="passwordless_technology_detail" msgid="6853928846532955882">"Криптографските клучеви дозволуваат да се најавувате без да зависите од лозинки. Треба само да користите отпечаток, препознавање лик, PIN или шема на повлекување за да го потврдите идентитетот и да создадете криптографски клуч."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Криптографија за јавни клучеви"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Според FIDO Alliance (во која членуваат Google, Apple, Microsoft и др.) и W3C-стандардите, криптографските клучеви користат криптографски парови на клучеви. За разлика од корисничките имиња и знаците што ги користиме за лозинки, се создава приватно-јавен пар клучеви за апликација или сајт. Приватниот клуч безбедно се чува на уредот или управникот со лозинки и го потврдува вашиот идентитет. Јавниот клуч се споделува со серверот на апликацијата или сајтот. Со соодветните клучеви, може инстантно да се регистрирате и најавувате."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Според FIDO Alliance (во која членуваат Google, Apple, Microsoft и др.) и W3C-стандардите, криптографските клучеви користат парови криптографски клучеви. За разлика од корисничките имиња и знаците што ги користиме за лозинки, се создава приватно-јавен пар клучеви за апликација или сајт. Приватниот клуч безбедно се чува на уредот или управникот со лозинки и го потврдува вашиот идентитет. Јавниот клуч се споделува со серверот на апликацијата или сајтот. Со соодветните клучеви, може инстантно да се регистрирате и најавувате."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Подобрена безбедност на сметката"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Секој клуч е поврзан само со апликацијата или веб-сајтот за кој бил создаден за да не може никогаш по грешка да се најавите на измамничка апликација или веб-сајт. Плус, кога серверите ги чуваат само јавните клучеви, хакирањето е многу потешко."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Беспрекорна транзиција"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Како што се движиме кон иднина без лозинки, лозинките сепак ќе бидат достапни покрај криптографските клучеви"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Иако се движиме кон иднина без лозинки, лозинките сепак ќе бидат достапни покрај криптографските клучеви"</string> <string name="choose_provider_title" msgid="8870795677024868108">"Изберете каде да ги зачувате вашите <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Изберете управник со лозинки за да ги зачувате вашите податоци и да се најавите побрзо следниот пат"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Да се создаде криптографски клуч за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Да се користи вашиот зачуван криптографски клуч за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Да се користи вашето зачувано најавување за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Изберете зачувано најавување за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Најавете се на друг начин"</string> <string name="snackbar_action" msgid="37373514216505085">"Прикажи ги опциите"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Продолжи"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управувајте со најавувањата"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Од друг уред"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Употребете друг уред"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Барањето е откажано од <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml index eb75149d9a80..9fcb24dbd6e2 100644 --- a/packages/CredentialManager/res/values-ml/strings.xml +++ b/packages/CredentialManager/res/values-ml/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി നിങ്ങൾ സംരക്ഷിച്ച പാസ്കീ ഉപയോഗിക്കണോ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി നിങ്ങൾ സംരക്ഷിച്ച സൈൻ ഇൻ ഉപയോഗിക്കണോ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി ഒരു സംരക്ഷിച്ച സൈൻ ഇൻ തിരഞ്ഞെടുക്കുക"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"മറ്റൊരു രീതിയിൽ സൈൻ ഇൻ ചെയ്യുക"</string> <string name="snackbar_action" msgid="37373514216505085">"ഓപ്ഷനുകൾ കാണുക"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"തുടരുക"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"സൈൻ ഇന്നുകൾ മാനേജ് ചെയ്യുക"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"മറ്റൊരു ഉപകരണത്തിൽ നിന്ന്"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"മറ്റൊരു ഉപകരണം ഉപയോഗിക്കുക"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"അഭ്യർത്ഥന <xliff:g id="APP_NAME">%1$s</xliff:g> റദ്ദാക്കി"</string> </resources> diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml index cf6a337713d8..aebffa152599 100644 --- a/packages/CredentialManager/res/values-mn/strings.xml +++ b/packages/CredentialManager/res/values-mn/strings.xml @@ -14,13 +14,13 @@ <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Тэдгээрийг нууц үгний менежерт хадгалдаг бөгөөд ингэснээр та бусад төхөөрөмжид нэвтрэх боломжтой"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Passkey-н талаарх дэлгэрэнгүй"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Нууц үггүй технологи"</string> - <string name="passwordless_technology_detail" msgid="6853928846532955882">"Passkey нь танд нууц үгэнд найдалгүйгээр нэвтрэх боломжийг олгодог. Та таниулбараа баталгаажуулах болон passkey үүсгэхийн тулд ердөө хурууны хээ, царай танилт, ПИН эсвэл шудрах хээгээ ашиглах шаардлагатай."</string> + <string name="passwordless_technology_detail" msgid="6853928846532955882">"Passkey нь танд нууц үгэнд найдалгүйгээр нэвтрэх боломжийг олгодог. Та хувийн мэдээллээ баталгаажуулах болон passkey үүсгэхийн тулд ердөө хурууны хээ, царай танилт, ПИН эсвэл шудрах хээгээ ашиглах шаардлагатай."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Нийтийн түлхүүрийн криптограф"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Холбоодын (Google, Apple, Microsoft ба бусад багтдаг) W3C стандартад тулгуурлан passkey нь криптограф түлхүүрийн хослолыг ашигладаг. Хэрэглэгчийн нэр, бидний нууц үгэнд ашигладаг тэмдэгтийн мөрөөс ялгаатай хувийн-нийтийн түлхүүрийн хослолыг апп эсвэл вебсайтад үүсгэдэг. Хувийн түлхүүрийг таны төхөөрөмж эсвэл нууц үгний менежерт аюулгүй хадгалдаг бөгөөд үүнийг таны таниулбарыг баталгаажуулахад ашигладаг. Нийтийн түлхүүрийг апп эсвэл вебсайтын сервертэй хуваалцдаг. Харгалзах түлхүүрээр та даруй бүртгүүлэх, нэвтрэх боломжтой."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Passkey нь FIDO Холбоо (Google, Apple, Microsoft ба бусад багтдаг) болон W3C стандартад тулгуурлан криптограф түлхүүрийн хослолыг ашигладаг. Хэрэглэгчийн нэр, бидний нууц үгэнд ашигладаг тэмдэгтийн мөрөөс ялгаатай хувийн-нийтийн түлхүүрийн хослолыг апп эсвэл вебсайтад үүсгэдэг. Хувийн түлхүүрийг таны төхөөрөмж эсвэл нууц үгний менежерт аюулгүй хадгалдаг бөгөөд үүнийг таны хувийн мэдээллийг баталгаажуулахад ашигладаг. Нийтийн түлхүүрийг апп эсвэл вебсайтын сервертэй хуваалцдаг. Харгалзах түлхүүрээр та даруй бүртгүүлэх, нэвтрэх боломжтой."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Бүртгэлийн сайжруулсан аюулгүй байдал"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Түлхүүр тус бүрийг тэдгээрийг зориулж үүсгэсэн апп эсвэл вебсайттай нь тусгайлан холбодог бөгөөд ингэснээр та залилан мэхэлсэн апп эсвэл вебсайтад санамсаргүй байдлаар хэзээ ч нэвтрэхгүй. Түүнчлэн зөвхөн нийтийн түлхүүрийг хадгалж буй серверүүдийг хакердахад илүү хэцүү байдаг."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Саадгүй шилжилт"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Бид нууц үггүй ирээдүй рүү урагшлахын хэрээр нууц үг нь passkey-н хамтаар боломжтой хэвээр байх болно"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Бид нууц үггүй ирээдүй рүү урагшлахын зэрэгцээ нууц үг нь passkey-н хамт боломжтой хэвээр байна"</string> <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g>-г хаана хадгалахаа сонгоно уу"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Мэдээллээ хадгалж, дараагийн удаа илүү хурдан нэвтрэхийн тулд нууц үгний менежерийг сонгоно уу"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>-д passkey үүсгэх үү?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д өөрийн хадгалсан passkey-г ашиглах уу?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д хадгалсан нэвтрэх мэдээллээ ашиглах уу?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д зориулж хадгалсан нэвтрэх мэдээллийг сонгоно уу"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Өөр аргаар нэвтрэх"</string> <string name="snackbar_action" msgid="37373514216505085">"Сонголт харах"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Үргэлжлүүлэх"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Нэвтрэлтийг удирдах"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Өөр төхөөрөмжөөс"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Өөр төхөөрөмж ашиглах"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml index 30538b5436a3..036b748e85fb 100644 --- a/packages/CredentialManager/res/values-mr/strings.xml +++ b/packages/CredentialManager/res/values-mr/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी तुमची सेव्ह केलेली पासकी वापरायची का?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी तुमचे सेव्ह केलेले साइन-इन वापरायचे का?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी सेव्ह केलेले साइन-इन निवडा"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"दुसऱ्या मार्गाने साइन इन करा"</string> <string name="snackbar_action" msgid="37373514216505085">"पर्याय पहा"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"पुढे सुरू ठेवा"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन-इन व्यवस्थापित करा"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"दुसऱ्या डिव्हाइस वरून"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"वेगळे डिव्हाइस वापरा"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ने विनंती रद्द केली आहे"</string> </resources> diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml index fb96a43857ac..e332db28939f 100644 --- a/packages/CredentialManager/res/values-ms/strings.xml +++ b/packages/CredentialManager/res/values-ms/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci laluan anda yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gunakan maklumat log masuk anda yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pilih log masuk yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Log masuk menggunakan cara lain"</string> <string name="snackbar_action" msgid="37373514216505085">"Lihat pilihan"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Teruskan"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Urus log masuk"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Daripada peranti lain"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan peranti yang lain"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Permintaan dibatalkan oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml index 8bd934d14cca..82ff5af59133 100644 --- a/packages/CredentialManager/res/values-my/strings.xml +++ b/packages/CredentialManager/res/values-my/strings.xml @@ -9,7 +9,7 @@ <string name="content_description_show_password" msgid="3283502010388521607">"စကားဝှက်ကို ပြရန်"</string> <string name="content_description_hide_password" msgid="6841375971631767996">"စကားဝှက်ကို ဖျောက်ရန်"</string> <string name="passkey_creation_intro_title" msgid="4251037543787718844">"လျှို့ဝှက်ကီးများဖြင့် ပိုလုံခြုံသည်"</string> - <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"လျှို့ဝှက်ကီးများဖြင့် ရှုပ်ထွေးသောစကားဝှက်များကို ပြုလုပ်ရန် (သို့) မှတ်မိရန် မလိုပါ"</string> + <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"လျှို့ဝှက်ကီးများသုံးလျှင် ရှုပ်ထွေးသောစကားဝှက်များကို ပြုလုပ်ရန် (သို့) မှတ်မိရန် မလိုပါ"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"လျှို့ဝှက်ကီးများမှာ သင်၏လက်ဗွေ၊ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ်သုံး၍ ပြုလုပ်ထားသော အသွင်ဝှက်ထားသည့် ဒစ်ဂျစ်တယ်ကီးများ ဖြစ်သည်"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"၎င်းတို့ကို စကားဝှက်မန်နေဂျာတွင် သိမ်းသဖြင့် အခြားစက်များတွင် လက်မှတ်ထိုးဝင်နိုင်ပါသည်"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"လျှို့ဝှက်ကီးများအကြောင်း ပိုပြရန်"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"သိမ်းထားသောလျှို့ဝှက်ကီးကို <xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သုံးမလား။"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သိမ်းထားသောလက်မှတ်ထိုးဝင်မှု သုံးမလား။"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သိမ်းထားသော လက်မှတ်ထိုးဝင်မှုကို ရွေးပါ"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"နောက်တစ်နည်းဖြင့် လက်မှတ်ထိုးဝင်ရန်"</string> <string name="snackbar_action" msgid="37373514216505085">"ရွေးစရာများကို ကြည့်ရန်"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ရှေ့ဆက်ရန်"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"လက်မှတ်ထိုးဝင်မှုများ စီမံခြင်း"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"စက်နောက်တစ်ခုမှ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"အခြားစက်သုံးရန်"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml index 7e722a5d3711..fd3c6684fc41 100644 --- a/packages/CredentialManager/res/values-nb/strings.xml +++ b/packages/CredentialManager/res/values-nb/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruke den lagrede tilgangsnøkkelen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vil du bruke den lagrede påloggingen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Velg en lagret pålogging for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Bruk en annen påloggingsmetode"</string> <string name="snackbar_action" msgid="37373514216505085">"Se alternativene"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Fortsett"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrer pålogginger"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en annen enhet"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Bruk en annen enhet"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml index 08bd9b77081d..d32a2b4d7735 100644 --- a/packages/CredentialManager/res/values-ne/strings.xml +++ b/packages/CredentialManager/res/values-ne/strings.xml @@ -18,11 +18,11 @@ <string name="public_key_cryptography_title" msgid="6751970819265298039">"सार्वजनिक कीको क्रिप्टोग्राफी"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO Alliance (जसमा Google, Apple, Microsoft र अन्य कम्पनी सामेल छन्) र W3C ले तोकेका मापदण्डहरूका आधारमा पासकीमा क्रिप्टोग्राफिक जोडी की प्रयोग गरिएको छ। निजी-सार्वजनिक जोडी की कुनै एप वा वेबसाइटका लागि बनाइन्छ। यो जोडी की युजरनेम र हामीले पासवर्डमा प्रयोग गर्ने वर्णहरूको स्ट्रिङभन्दा फरक हुन्छ। निजी की तपाईंको डिभाइस वा पासवर्ड म्यानेजरमा सुरक्षित रूपमा राखिन्छ र यसले तपाईंको पहिचान पुष्टि गर्छ। सार्वजनिक की चाहिँ एप वा वेबसाइटको सर्भरसँग सेयर गरिन्छ। तपाईं यी की प्रयोग गरी तुरुन्तै दर्ता वा साइन इन गर्न सक्नुहुन्छ।"</string> <string name="improved_account_security_title" msgid="1069841917893513424">"खाताको सुदृढ सुरक्षा"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"तपाईं कहिले पनि गल्तीले कुनै कपटपूर्ण एप वा वेबसाइटमा लग इन गर्न नसक्नुहोस् भन्नाका लागि हरेक की जुन एप वा वेबसाइटको लागि बनाइएको थियो त्यसलाई खास गरी सोही एप वा वेबसाइटसँग लिंक गरिन्छ। यसका साथै, सर्भरहरूले सार्वजनिक की मात्र राखिराख्ने भएकाले ह्याक गर्न झनै कठिन भएको छ।"</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"तपाईं कहिले पनि गल्तीले कुनै कपटपूर्ण एप वा वेबसाइटमा लग इन गर्न नसक्नुहोस् भन्नाका लागि हरेक की जुन एप वा वेबसाइटको लागि बनाइएको थियो त्यसलाई खास गरी सोही एप वा वेबसाइटसँग लिंक गरिन्छ। यसका साथै, सर्भरहरूले सार्वजनिक की मात्र राख्ने भएकाले ह्याक गर्न झनै कठिन हुन्छ।"</string> <string name="seamless_transition_title" msgid="5335622196351371961">"निर्बाध ट्रान्जिसन"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"हामी पासवर्डरहित भविष्यतर्फ बढ्दै गर्दा पासकीका साथसाथै पासवर्ड पनि उपलब्ध भइरहने छन्"</string> <string name="choose_provider_title" msgid="8870795677024868108">"तपाईं आफ्ना <xliff:g id="CREATETYPES">%1$s</xliff:g> कहाँ सेभ गर्न चाहनुहुन्छ भन्ने कुरा छनौट गर्नुहोस्"</string> - <string name="choose_provider_body" msgid="4967074531845147434">"कुनै पासवर्ड म्यानेजरमा आफ्नो जानकारी सेभ गरी अर्को पटक अझ छिटो साइन एन गर्नुहोस्"</string> + <string name="choose_provider_body" msgid="4967074531845147434">"कुनै पासवर्ड म्यानेजरमा आफ्नो जानकारी सेभ गरी अर्को पटक अझ छिटो साइन इन गर्नुहोस्"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> को पासकी बनाउने हो?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> को पासवर्ड सेभ गर्ने हो?"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> मा साइन गर्न प्रयोग गरिनु पर्ने जानकारी सेभ गर्ने हो?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"आफूले सेभ गरेको पासकी प्रयोग गरी <xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्ने हो?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"आफूले सेभ गरेको साइन इनसम्बन्धी जानकारी प्रयोग गरी <xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्ने हो?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्नका लागि सेभ गरिएका साइन इनसम्बन्धी जानकारी छनौट गर्नुहोस्"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"अर्कै विधि प्रयोग गरी साइन इन गर्नुहोस्"</string> <string name="snackbar_action" msgid="37373514216505085">"विकल्पहरू हेर्नुहोस्"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"जारी राख्नुहोस्"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इनसम्बन्धी विकल्पहरू व्यवस्थापन गर्नुहोस्"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"अर्को डिभाइसका लागि"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"अर्कै डिभाइस प्रयोग गरी हेर्नुहोस्"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml index f9892b00e8f0..4b1313099e64 100644 --- a/packages/CredentialManager/res/values-nl/strings.xml +++ b/packages/CredentialManager/res/values-nl/strings.xml @@ -16,17 +16,17 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"Wachtwoordloze technologie"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Met een toegangssleutel heb je geen wachtwoord meer nodig om in te loggen. Als je op deze manier wilt inloggen, moet je je identiteit bevestigen met je vingerafdruk, gezichtsherkenning, pincode of swipepatroon en een toegangssleutel maken."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Cryptografie met openbare sleutels"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Toegangssleutels maken gebruik van cryptografische sleutelparen in overeenstemming met de FIDO Alliance (waartoe onder andere Google, Apple en Microsoft behoren) en W3C-standaarden. Anders dan de combinatie van gebruikersnaam en de tekenreeks die het wachtwoord vormt, wordt bij toegangssleutels voor elke app of website een privé/openbaar sleutelpaar gemaakt. De privésleutel wordt beveiligd opgeslagen op je apparaat of in de wachtwoordmanager om je identiteit te bevestigen. De openbare sleutel wordt gedeeld met de server van de app of website. Als de sleutels overeenkomen, kun je je meteen registreren en inloggen."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Toegangssleutels maken gebruik van cryptografische sleutelparen in overeenstemming met de FIDO Alliance (waartoe onder andere Google, Apple en Microsoft behoren) en W3C-standaarden. Anders dan de combinatie van gebruikersnaam en de tekenreeks die het wachtwoord vormt, wordt bij toegangssleutels voor elke app of website een privé/openbaar sleutelpaar gemaakt. De privésleutel wordt beveiligd opgeslagen op je apparaat of in de wachtwoordmanager en bevestigt je identiteit. De openbare sleutel wordt gedeeld met de server van de app of website. Als de sleutels overeenkomen, kun je je meteen registreren en inloggen."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Verbeterde accountbeveiliging"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Elke sleutel is exclusief gekoppeld aan de app of website waarvoor deze is gemaakt. Je kunt dus nooit per ongeluk inloggen bij een bedrieglijke app of website. Bovendien bewaren servers alleen openbare sleutels, wat hacken een stuk lastiger maakt."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Naadloze overgang"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"We zijn op weg naar een wachtwoordloze toekomst, maar naast toegangssleutels kun je nog steeds gebruikmaken van wachtwoorden."</string> - <string name="choose_provider_title" msgid="8870795677024868108">"Kies waar je je <xliff:g id="CREATETYPES">%1$s</xliff:g> wilt opslaan"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"We zijn op weg naar een toekomst zonder wachtwoorden, maar je kunt ze nog steeds gebruiken naast toegangssleutels."</string> + <string name="choose_provider_title" msgid="8870795677024868108">"Kiezen waar je je <xliff:g id="CREATETYPES">%1$s</xliff:g> wilt opslaan"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Selecteer een wachtwoordmanager om je informatie op te slaan en de volgende keer sneller in te loggen"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Toegangssleutel maken voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"Wachtwoord opslaan voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Inloggegevens opslaan voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> - <string name="passkey" msgid="632353688396759522">"toegangssleutel"</string> + <string name="passkey" msgid="632353688396759522">"Toegangssleutel"</string> <string name="password" msgid="6738570945182936667">"wachtwoord"</string> <string name="passkeys" msgid="5733880786866559847">"toegangssleutels"</string> <string name="passwords" msgid="5419394230391253816">"wachtwoorden"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Je opgeslagen toegangssleutel gebruiken voor <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Je opgeslagen inloggegevens voor <xliff:g id="APP_NAME">%1$s</xliff:g> gebruiken?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Opgeslagen inloggegevens kiezen voor <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Op een andere manier inloggen"</string> <string name="snackbar_action" msgid="37373514216505085">"Opties bekijken"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Doorgaan"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Inloggegevens beheren"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via een ander apparaat"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Een ander apparaat gebruiken"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml index f91f5a13b50c..068b4150e488 100644 --- a/packages/CredentialManager/res/values-or/strings.xml +++ b/packages/CredentialManager/res/values-or/strings.xml @@ -10,7 +10,7 @@ <string name="content_description_hide_password" msgid="6841375971631767996">"ପାସୱାର୍ଡ ଲୁଚାନ୍ତୁ"</string> <string name="passkey_creation_intro_title" msgid="4251037543787718844">"ପାସକୀ ସହ ଅଧିକ ସୁରକ୍ଷିତ"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"ପାସକୀଗୁଡ଼ିକ ସହ ଆପଣଙ୍କୁ ଜଟିଳ ପାସୱାର୍ଡଗୁଡ଼ିକ ତିଆରି କରିବା କିମ୍ବା ମନେରଖିବାର ଆବଶ୍ୟକତା ନାହିଁ"</string> - <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ପାସକୀଗୁଡ଼ିକ ହେଉଛି ଆପଣ ଆପଣଙ୍କ ଟିପଚିହ୍ନ, ଫେସ କିମ୍ବା ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରି ତିଆରି କରୁଥିବା ଏକକ୍ରିପ୍ଟ କରାଯାଇଥିବା ଡିଜିଟାଲ କୀ"</string> + <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"ପାସକୀ ହେଉଛି ଏନକ୍ରିପ୍ଟ ହୋଇଥିବା ଡିଜିଟାଲ କୀ\' ଯାହା ଆପଣ ଆପଣଙ୍କ ଟିପଚିହ୍ନ, ଫେସ କିମ୍ବା ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରି ତିଆରି କରନ୍ତି"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ସେଗୁଡ଼ିକୁ ଏକ Password Managerରେ ସେଭ କରାଯାଏ, ଯାହା ଫଳରେ ଆପଣ ଅନ୍ୟ ଡିଭାଇସଗୁଡ଼ିକରେ ସାଇନ ଇନ କରିପାରିବେ"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"ପାସକୀଗୁଡ଼ିକ ବିଷୟରେ ଅଧିକ"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"ପାସୱାର୍ଡ ବିହୀନ ଟେକ୍ନୋଲୋଜି"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଆପଣଙ୍କ ପାସକୀ ବ୍ୟବହାର କରିବେ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଆପଣଙ୍କ ସାଇନ-ଇନ ବ୍ୟବହାର କରିବେ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଏକ ସାଇନ-ଇନ ବାଛନ୍ତୁ"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ଅନ୍ୟ ଏକ ଉପାୟରେ ସାଇନ ଇନ କରନ୍ତୁ"</string> <string name="snackbar_action" msgid="37373514216505085">"ବିକଳ୍ପଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ଜାରି ରଖନ୍ତୁ"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ସାଇନ-ଇନ ପରିଚାଳନା କରନ୍ତୁ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ଅନ୍ୟ ଏକ ଡିଭାଇସରୁ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ଏକ ଭିନ୍ନ ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml index 64c1149f7906..c023fbd6a35c 100644 --- a/packages/CredentialManager/res/values-pa/strings.xml +++ b/packages/CredentialManager/res/values-pa/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਆਪਣੀ ਰੱਖਿਅਤ ਕੀਤੀ ਪਾਸਕੀ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਆਪਣੀ ਰੱਖਿਅਤ ਕੀਤੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਰੱਖਿਅਤ ਕੀਤੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਚੁਣੋ"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ਕਿਸੇ ਹੋਰ ਤਰੀਕੇ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰੋ"</string> <string name="snackbar_action" msgid="37373514216505085">"ਵਿਕਲਪ ਦੇਖੋ"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ਜਾਰੀ ਰੱਖੋ"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ਸਾਈਨ-ਇਨਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ਹੋਰ ਡੀਵਾਈਸ ਤੋਂ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ਵੱਖਰੇ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml index 787a3ba86508..0c844624a7ab 100644 --- a/packages/CredentialManager/res/values-pl/strings.xml +++ b/packages/CredentialManager/res/values-pl/strings.xml @@ -16,7 +16,7 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"Technologia niewymagająca haseł"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Klucze umożliwiają logowanie się bez konieczności stosowania haseł. Wystarczy użyć odcisku palca, rozpoznawania twarzy, kodu PIN lub wzoru, aby potwierdzić tożsamość i utworzyć klucz."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kryptografia klucza publicznego"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Zgodnie z zasadami FIDO Alliance (stowarzyszenia zrzeszającego m.in. Google, Apple i Microsoft) oraz standardami W3C klucze opierają się kluczach kryptograficznych. W odróżnieniu od nazw użytkownika i ciągów znaków stanowiących hasła pary kluczy prywatnych i publicznych są tworzone dla konkretnych aplikacji i stron. Klucz prywatny jest bezpiecznie przechowywany na urządzeniu lub w menedżerze haseł i potwierdza Twoją tożsamość. Klucz publiczny jest udostępniany serwerowi aplikacji lub strony. Mając odpowiednie klucze, od razu się zarejestrujesz i zalogujesz."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Zgodnie z zasadami FIDO Alliance (stowarzyszenia zrzeszającego m.in. Google, Apple i Microsoft) oraz standardami W3C klucze opierają się na kluczach kryptograficznych. W odróżnieniu od nazw użytkownika i ciągów znaków stanowiących hasła pary kluczy prywatnych i publicznych są tworzone dla konkretnych aplikacji i stron. Klucz prywatny jest bezpiecznie przechowywany na urządzeniu lub w menedżerze haseł i potwierdza Twoją tożsamość. Klucz publiczny jest udostępniany serwerowi aplikacji lub strony. Mając odpowiednie klucze, od razu się zarejestrujesz i zalogujesz."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Zwiększone bezpieczeństwo konta"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Każdy klucz jest połączony wyłącznie z aplikacją lub stroną, dla której został utworzony, więc nie zalogujesz się przypadkowo w fałszywej aplikacji ani na fałszywej stronie. Ponadto na serwerach są przechowywane wyłącznie klucze publiczne, co znacznie utrudnia hakowanie."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Płynne przechodzenie"</string> @@ -31,7 +31,7 @@ <string name="passkeys" msgid="5733880786866559847">"klucze"</string> <string name="passwords" msgid="5419394230391253816">"hasła"</string> <string name="sign_ins" msgid="4710739369149469208">"dane logowania"</string> - <string name="sign_in_info" msgid="2627704710674232328">"informacje dotyczące logowania"</string> + <string name="sign_in_info" msgid="2627704710674232328">"dane logowania"</string> <string name="save_credential_to_title" msgid="3172811692275634301">"Zapisać <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> w:"</string> <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Utworzyć klucz na innym urządzeniu?"</string> <string name="use_provider_for_all_title" msgid="4201020195058980757">"Używać usługi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> w przypadku wszystkich danych logowania?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Użyć zapisanego klucza dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Użyć zapisanych danych logowania dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Wybierz zapisane dane logowania dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Zaloguj się w inny sposób"</string> <string name="snackbar_action" msgid="37373514216505085">"Wyświetl opcje"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Dalej"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Zarządzanie danymi logowania"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na innym urządzeniu"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Użyj innego urządzenia"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml index 3250fb02a7c9..6e90159c4e55 100644 --- a/packages/CredentialManager/res/values-pt-rBR/strings.xml +++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml @@ -49,9 +49,11 @@ <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Voltar à página anterior"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Fechar"</string> <string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dispensar"</string> - <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar suas informações de login salvas para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolher um login salvo para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Fazer login de outra forma"</string> <string name="snackbar_action" msgid="37373514216505085">"Conferir opções"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gerenciar logins"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Solicitação cancelada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml index 9bf350c224e3..19672d494b9b 100644 --- a/packages/CredentialManager/res/values-pt-rPT/strings.xml +++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml @@ -14,9 +14,9 @@ <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"São guardadas num gestor de palavras-passe para que possa iniciar sessão noutros dispositivos"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Mais acerca das chaves de acesso"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Tecnologia sem palavras-passe"</string> - <string name="passwordless_technology_detail" msgid="6853928846532955882">"As chaves de acesso permitem-lhe iniciar sessão sem depender das palavras-passe. Basta usar a impressão digital, o reconhecimento facial, o PIN ou o padrão de deslize para validar a sua identidade e criar uma token de acesso."</string> + <string name="passwordless_technology_detail" msgid="6853928846532955882">"As chaves de acesso permitem-lhe iniciar sessão sem depender das palavras-passe. Basta usar a impressão digital, o reconhecimento facial, o PIN ou o padrão de deslize para validar a sua identidade e criar uma chave de acesso."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Criptografia de chaves públicas"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Baseadas na FIDO Alliance e no W3C, as palavras de acesso usam pares de chaves criptográficas. Ao contrário do nome de utilizador e da string de carateres das palavras-passe, cria-se um par de chaves públicas/privadas para a app ou Website. A chave privada é armazenada de forma segura no dispositivo ou gestor de palavras-passe e confirma a identidade. A chave pública é partilhada com o servidor do Website ou app. Com as chaves correspondentes, pode registar-se e iniciar sessão instantaneamente."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Baseadas na FIDO Alliance e no W3C, as chaves de acesso usam pares de chaves criptográficas. Ao contrário do nome de utilizador e da string de carateres das palavras-passe, cria-se um par de chaves públicas/privadas para a app ou Website. A chave privada é armazenada de forma segura no dispositivo ou gestor de palavras-passe e confirma a identidade. A chave pública é partilhada com o servidor do Website ou app. Com as chaves correspondentes, pode registar-se e iniciar sessão instantaneamente."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Segurança melhorada nas contas"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Cada chave é exclusivamente associada à app ou ao Website para o qual foi criada, por isso, nunca pode iniciar sessão numa app ou num Website fraudulento acidentalmente. Além disso, os servidores só mantêm chaves públicas, o que dificulta a pirataria."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Transição sem complicações"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar a sua chave de acesso guardada na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar o seu início de sessão guardado na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolha um início de sessão guardado para a app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Iniciar sessão de outra forma"</string> <string name="snackbar_action" msgid="37373514216505085">"Ver opções"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Faça a gestão dos inícios de sessão"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use um dispositivo diferente"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Pedido cancelado pela app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml index 3250fb02a7c9..6e90159c4e55 100644 --- a/packages/CredentialManager/res/values-pt/strings.xml +++ b/packages/CredentialManager/res/values-pt/strings.xml @@ -49,9 +49,11 @@ <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Voltar à página anterior"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Fechar"</string> <string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dispensar"</string> - <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar suas informações de login salvas para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolher um login salvo para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Fazer login de outra forma"</string> <string name="snackbar_action" msgid="37373514216505085">"Conferir opções"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gerenciar logins"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Solicitação cancelada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml index 96caac73c7d9..5f72f84a048b 100644 --- a/packages/CredentialManager/res/values-ro/strings.xml +++ b/packages/CredentialManager/res/values-ro/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Folosești cheia de acces salvată pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Folosești datele de conectare salvate pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Alege o conectare salvată pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Conectează-te altfel"</string> <string name="snackbar_action" msgid="37373514216505085">"Afișează opțiunile"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuă"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionează acreditările"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De pe alt dispozitiv"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Folosește alt dispozitiv"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml index 4e7ff7d1e0b7..8baddbd80ed2 100644 --- a/packages/CredentialManager/res/values-ru/strings.xml +++ b/packages/CredentialManager/res/values-ru/strings.xml @@ -10,13 +10,13 @@ <string name="content_description_hide_password" msgid="6841375971631767996">"Скрыть пароль"</string> <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Ключи доступа безопаснее"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Благодаря ключам доступа вам не придется создавать или запоминать сложные пароли."</string> - <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Ключ доступа – это зашифрованное цифровое удостоверение, которое создается с использованием отпечатка пальца, функции фейсконтроля или блокировки экрана."</string> + <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Ключ доступа – это зашифрованное цифровое удостоверение, которое создается на основе отпечатка пальца, снимка для фейсконтроля, PIN-кода или графического ключа."</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Данные хранятся в менеджере паролей, чтобы вы могли входить в аккаунт на других устройствах."</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Подробнее о ключах доступа"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Технология аутентификации без пароля"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Ключи доступа позволяют входить в аккаунт без ввода пароля. Чтобы подтвердить личность и создать ключ доступа, достаточно использовать отпечаток пальца, распознавание по лицу, PIN-код или графический ключ."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Шифрование с помощью открытого ключа"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Согласно стандартам W3C и ассоциации FIDO Alliance (Google, Apple, Microsoft и др.) для создания ключей доступа используются пары криптографических ключей. В приложении или на сайте создается не имя пользователя и пароль, а пара открытого и закрытого ключей. Закрытый ключ хранится на вашем устройстве или в менеджере паролей и нужен для подтверждения личности. Открытый ключ передается приложению или серверу сайта. Подходящие ключи помогают быстро войти в аккаунт или зарегистрироваться."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Согласно стандартам W3C и ассоциации FIDO Alliance (Google, Apple, Microsoft и др.) для создания ключей доступа используются пары ключей шифрования. В приложении или на сайте создается не имя пользователя и пароль, а пара ключей – открытый и закрытый. Закрытый хранится на вашем устройстве или в менеджере паролей и нужен для подтверждения личности, а открытый передается приложению или серверу сайта. Когда ключи соответствуют друг другу, вы можете быстро зарегистрироваться или войти в аккаунт."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Повышенная безопасность аккаунта"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Каждый ключ связан только с тем приложением или сайтом, для которого был создан, поэтому вы не сможете по ошибке войти в приложение или на сайт мошенников. Кроме того, на серверах хранятся только открытые ключи, что служит дополнительной защитой от взлома."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Плавный переход"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Использовать сохраненный ключ доступа для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Использовать сохраненные учетные данные для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Выберите сохраненные данные для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Войти другим способом"</string> <string name="snackbar_action" msgid="37373514216505085">"Показать варианты"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Продолжить"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управление входом"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"С другого устройства"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Использовать другое устройство"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml index 95e326c7060c..1b3b4edf960e 100644 --- a/packages/CredentialManager/res/values-si/strings.xml +++ b/packages/CredentialManager/res/values-si/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා ඔබේ සුරැකි මුරයතුර භාවිතා කරන්න ද?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා ඔබේ සුරැකි පුරනය භාවිතා කරන්න ද?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා සුරැකි පුරනයක් තෝරා ගන්න"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"වෙනත් ආකාරයකින් පුරන්න"</string> <string name="snackbar_action" msgid="37373514216505085">"විකල්ප බලන්න"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ඉදිරියට යන්න"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"පුරනය වීම් කළමනාකරණය කරන්න"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"වෙනත් උපාංගයකින්"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"වෙනස් උපාංගයක් භාවිතා කරන්න"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml index 48cece1df56d..965529067d02 100644 --- a/packages/CredentialManager/res/values-sk/strings.xml +++ b/packages/CredentialManager/res/values-sk/strings.xml @@ -10,17 +10,17 @@ <string name="content_description_hide_password" msgid="6841375971631767996">"Skryť heslo"</string> <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Bezpečnejšie s prístupovými kľúčmi"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Ak máte prístupové kľúče, nemusíte vytvárať ani si pamätať zložité heslá"</string> - <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Prístupové kľúče sú šifrované digitálne kľúče, ktoré môžete vytvoriť odtlačkom prsta, tvárou alebo zámkou obrazovky."</string> + <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Prístupové kľúče sú šifrované digitálne kľúče, ktoré môžete vytvoriť odtlačkom prsta, tvárou alebo zámkou obrazovky"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ukladajú sa do správcu hesiel, aby ste sa mohli prihlasovať v iných zariadeniach"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Viac o prístupových kľúčoch"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Technológia bez hesiel"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Prístupové kľúče vám umožňujú prihlásiť sa bez použitia hesiel. Stačí overiť totožnosť odtlačkom prsta, rozpoznávaním tváre, kódom PIN alebo vzorom potiahnutia a vytvoriť prístupový kľúč."</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kryptografia verejných kľúčov"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Prístup. kľúče firiem patriacich do združenia FIDO (zahŕňajúceho Google, Apple, Microsoft a ďalšie) využívajú páry kryptograf. kľúčov a štandardy W3C. Na rozdiel od použív. mena a reťazca znakov využívaných v prípade hesiel sa pár súkr. a verej. kľúča vytvára pre aplikáciu alebo web. Súkr. kľúč sa bezpečne ukladá v zar. či správcovi hesiel a slúži na overenie totožnosti. Verej. kľúč sa zdieľa so serverom danej aplik. alebo webu. Príslušnými kľúčami sa môžete okamžite registrovať a prihlasovať."</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Prístupové kľúče založené na štandardoch W3C a aliancie FIDO (do ktorej patria Google, Apple, Microsoft a ďalší) používajú páry kryptografických kľúčov. Na rozdiel od používateľského mena a hesla sa pre každú aplikáciu alebo web vytvára jeden pár kľúčov (súkromný a verejný). Súkromný kľúč, bezpečne uložený v zariadení alebo v správcovi hesiel, potvrdzuje vašu identitu. Verejný kľúč sa zdieľa so serverom aplikácie alebo stránky. Vďaka zhodným kľúčom je registrácia a prihlásenie okamžité."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Lepšie zabezpečenie účtu"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Každý kľúč je výhradne prepojený s aplikáciou alebo webom, pre ktorý bol vytvorený, takže sa nikdy nemôžete omylom prihlásiť do podvodnej aplikácie alebo na podvodnom webe. Servery navyše uchovávajú iba verejné kľúče, čím podstatne sťažujú hackovanie."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Plynulý prechod"</string> - <string name="seamless_transition_detail" msgid="3440478759491650823">"Blížime sa k budúcnosti bez hesiel, ale heslá budú popri prístupových kľúčoch stále k dispozícii"</string> + <string name="seamless_transition_detail" msgid="3440478759491650823">"Hoci smerujeme k budúcnosti bez hesiel, popri prístupových kľúčoch budú naďalej k dispozícii i heslá."</string> <string name="choose_provider_title" msgid="8870795677024868108">"Vyberte, kam sa majú ukladať <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Vyberte správcu hesiel, do ktorého sa budú ukladať vaše údaje, aby ste sa nabudúce mohli rýchlejšie prihlásiť"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Chcete vytvoriť prístupový kľúč pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> použiť uložený prístupový kľúč?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> použiť uložené prihlasovacie údaje?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Vyberte uložené prihlasovacie údaje pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prihlásiť sa inak"</string> <string name="snackbar_action" msgid="37373514216505085">"Zobraziť možnosti"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Pokračovať"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Spravovať prihlasovacie údaje"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z iného zariadenia"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použiť iné zariadenie"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml index 5fde9ffb524c..433a06d05ee8 100644 --- a/packages/CredentialManager/res/values-sl/strings.xml +++ b/packages/CredentialManager/res/values-sl/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite uporabiti shranjeni ključ za dostop do aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite uporabiti shranjene podatke za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Izberite shranjene podatke za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijava na drug način"</string> <string name="snackbar_action" msgid="37373514216505085">"Prikaz možnosti"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Naprej"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljanje podatkov za prijavo"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Iz druge naprave"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Uporaba druge naprave"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml index 957fd35a1a29..7697fbde5b03 100644 --- a/packages/CredentialManager/res/values-sq/strings.xml +++ b/packages/CredentialManager/res/values-sq/strings.xml @@ -11,7 +11,7 @@ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Më e sigurt me çelësat e kalimit"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Me çelësat e kalimit, nuk ka nevojë të krijosh ose të mbash mend fjalëkalime të ndërlikuara"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Çelësat e kalimit kanë çelësa dixhitalë të enkriptuar që ti i krijon duke përdorur gjurmën e gishtit, fytyrën ose kyçjen e ekranit"</string> - <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ata ruhen te një menaxher fjalëkalimesh, në mënyrë që mund të identifikohesh në pajisje të tjera"</string> + <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Ata ruhen te një menaxher fjalëkalimesh, në mënyrë që të mund të identifikohesh në pajisje të tjera"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Më shumë rreth çelësave të kalimit"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Teknologji pa fjalëkalime"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Çelësat e kalimit të lejojnë të identifikohesh pa u mbështetur te fjalëkalimet. Të duhet vetëm të përdorësh gjurmën e gishtit, njohjen e fytyrës, PIN-in ose të rrëshqasësh motivin për të verifikuar identitetin dhe për të krijuar një çelës kalimi."</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Të përdoret fjalëkalimi yt i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Të përdoret identifikimi yt i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Zgjidh një identifikim të ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Identifikohu me një mënyrë tjetër"</string> <string name="snackbar_action" msgid="37373514216505085">"Shiko opsionet"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Vazhdo"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Identifikimet e menaxhimit"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Nga një pajisje tjetër"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Përdor një pajisje tjetër"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"Kërkesa u anulua nga <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> </resources> diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml index b550c1bdd960..2827df389097 100644 --- a/packages/CredentialManager/res/values-sr/strings.xml +++ b/packages/CredentialManager/res/values-sr/strings.xml @@ -21,7 +21,7 @@ <string name="improved_account_security_detail" msgid="9123750251551844860">"Сваки кључ је искључиво повезан са апликацијом или веб-сајтом за које је направљен, па никад не можете грешком да се пријавите у апликацију или на веб-сајт који служе за превару. Осим тога, са серверима који чувају само јавне кључеве хаковање је много теже."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Беспрекоран прелаз"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"Како се крећемо ка будућности без лозинки, лозинке ће и даље бити доступне уз приступне кодове"</string> - <string name="choose_provider_title" msgid="8870795677024868108">"Одаберите где ћете сачувати ставке <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> + <string name="choose_provider_title" msgid="8870795677024868108">"Одаберите где ћете сачувати: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string> <string name="choose_provider_body" msgid="4967074531845147434">"Изаберите менаџера лозинки да бисте сачували податке и брже се пријавили следећи пут"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Желите да направите приступни кôд за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"Желите да сачувате лозинку за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string> @@ -32,7 +32,7 @@ <string name="passwords" msgid="5419394230391253816">"лозинке"</string> <string name="sign_ins" msgid="4710739369149469208">"пријављивања"</string> <string name="sign_in_info" msgid="2627704710674232328">"подаци за пријављивање"</string> - <string name="save_credential_to_title" msgid="3172811692275634301">"Сачувај ставку <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> у"</string> + <string name="save_credential_to_title" msgid="3172811692275634301">"Сачувај <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> у"</string> <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Желите да направите приступни кôд на другом уређају?"</string> <string name="use_provider_for_all_title" msgid="4201020195058980757">"Желите да за сва пријављивања користите: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string> <string name="use_provider_for_all_description" msgid="1998772715863958997">"Овај менаџер лозинки за <xliff:g id="USERNAME">%1$s</xliff:g> ће чувати лозинке и приступне кодове да бисте се лако пријављивали"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Желите да користите сачувани приступни кôд за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Желите да користите сачуване податке за пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Одаберите сачувано пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Пријавите се на други начин"</string> <string name="snackbar_action" msgid="37373514216505085">"Прикажи опције"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Настави"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управљајте пријављивањима"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Са другог уређаја"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Користи други уређај"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml index 440ee6e42c0f..b78de0cb2b54 100644 --- a/packages/CredentialManager/res/values-sv/strings.xml +++ b/packages/CredentialManager/res/values-sv/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vill du använda din sparade nyckel för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vill du använda dina sparade inloggningsuppgifter för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Välj en sparad inloggning för <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Logga in på ett annat sätt"</string> <string name="snackbar_action" msgid="37373514216505085">"Visa alternativ"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Fortsätt"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Hantera inloggningar"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via en annan enhet"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Använd en annan enhet"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml index 6f71ed7d5d89..43564c76f7a9 100644 --- a/packages/CredentialManager/res/values-sw/strings.xml +++ b/packages/CredentialManager/res/values-sw/strings.xml @@ -8,15 +8,15 @@ <string name="string_learn_more" msgid="4541600451688392447">"Pata maelezo zaidi"</string> <string name="content_description_show_password" msgid="3283502010388521607">"Onyesha nenosiri"</string> <string name="content_description_hide_password" msgid="6841375971631767996">"Ficha nenosiri"</string> - <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Ni salama ukitumia funguo za siri"</string> + <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Salama zaidi ukitumia funguo za siri"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Kwa kutumia funguo za siri, huhitaji kuunda au kukumbuka manenosiri changamano"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Funguo za siri ni funguo dijitali zilizosimbwa kwa njia fiche unazounda kwa kutumia alama yako ya kidole, uso au mbinu ya kufunga skrini"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Vyote huhifadhiwa kwenye kidhibiti cha manenosiri, ili uweze kuingia katika akaunti kwenye vifaa vingine"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"Maelezo zaidi kuhusu funguo za siri"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Teknolojia isiyotumia manenosiri"</string> - <string name="passwordless_technology_detail" msgid="6853928846532955882">"Funguo za siri zinakuruhusu uingie katika akaunti bila kutegemea manenosiri. Unapaswa tu kutumia alama yako ya kidole, kipengele cha utambuzi wa uso, PIN au mchoro wa kutelezesha ili uthibitishe utambulisho wako na uunde ufunguo wa siri."</string> - <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kriptographia ya ufunguo wa umma"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Kulingana na Ushirikiano wa FIDO (unaojumuisha Google, Apple, Microsoft na zaidi) na viwango vya W3C, funguo za siri hutumia jozi ya funguo za kriptografia. Tofauti na jina la mtumiaji na mfuatano wa herufi tunazotumia kwa ajili ya manenosiri, jozi ya funguo binafsi na za umma imeundwa kwa ajili ya programu au tovuti. Ufunguo binafsi unatunzwa kwa usalama kwenye kifaa chako au kidhibiti cha manenosiri na huthibitisha utambulisho wako. Ufunguo wa umma unashirikiwa na seva ya programu au tovuti. Kwa funguo zinazolingana, unaweza kujisajili na kuingia katika akaunti papo hapo."</string> + <string name="passwordless_technology_detail" msgid="6853928846532955882">"Funguo za siri zinakuruhusu uingie katika akaunti bila kutegemea manenosiri. Unahitaji tu kutumia alama yako ya kidole, kipengele cha utambuzi wa uso, PIN au mchoro wa kutelezesha ili kuthibitisha utambulisho wako na kuunda ufunguo wa siri."</string> + <string name="public_key_cryptography_title" msgid="6751970819265298039">"Kriptografia ya funguo za umma"</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Kulingana na Muungano wa FIDO (unaojumuisha Google, Apple, Microsoft na zaidi) na viwango vya W3C, funguo za siri hutumia jozi ya funguo za kriptografia. Tofauti na jina la mtumiaji na mfuatano wa herufi tunazotumia kwa ajili ya manenosiri, jozi ya funguo binafsi na za umma imeundwa kwa ajili ya programu au tovuti. Ufunguo binafsi hutunzwa kwa usalama kwenye kifaa chako au kidhibiti cha manenosiri na huthibitisha utambulisho wako. Ufunguo wa umma hushirikiwa na seva ya programu au tovuti. Ukiwa na funguo zinazolingana, unaweza kujisajili na kuingia katika akaunti papo hapo."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Ulinzi wa akaunti ulioboreshwa"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Kila ufunguo umeunganishwa kwa upekee na programu au tovuti husika, kwa hivyo kamwe huwezi kuingia katika akaunti ya programu au tovuti ya kilaghai kwa bahati mbaya. Pia, kwa kuwa seva huhifadhi tu funguo za umma, udukuzi si rahisi."</string> <string name="seamless_transition_title" msgid="5335622196351371961">"Mabadiliko rahisi"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Ungependa kutumia ufunguo wa siri uliohifadhiwa wa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Ungependa kutumia kitambulisho kilichohifadhiwa cha kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Chagua vitambulisho vilivyohifadhiwa kwa ajili ya kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Ingia katika akaunti kwa kutumia njia nyingine"</string> <string name="snackbar_action" msgid="37373514216505085">"Angalia chaguo"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Endelea"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Dhibiti michakato ya kuingia katika akaunti"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kutoka kwenye kifaa kingine"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Tumia kifaa tofauti"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml index 593aac32416d..f4eb46c8b931 100644 --- a/packages/CredentialManager/res/values-ta/strings.xml +++ b/packages/CredentialManager/res/values-ta/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட கடவுக்குறியீட்டைப் பயன்படுத்தவா?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட உள்நுழைவுத் தகவலைப் பயன்படுத்தவா?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட உள்நுழைவுத் தகவலைத் தேர்வுசெய்யவும்"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"வேறு முறையில் உள்நுழைக"</string> <string name="snackbar_action" msgid="37373514216505085">"விருப்பங்களைக் காட்டு"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"தொடர்க"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"உள்நுழைவுகளை நிர்வகித்தல்"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"மற்றொரு சாதனத்திலிருந்து பயன்படுத்து"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"வேறு சாதனத்தைப் பயன்படுத்து"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml index ae6149df0fb5..297e559def78 100644 --- a/packages/CredentialManager/res/values-te/strings.xml +++ b/packages/CredentialManager/res/values-te/strings.xml @@ -11,7 +11,7 @@ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"పాస్-కీలతో సురక్షితంగా పేమెంట్ చేయవచ్చు"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"పాస్-కీలతో, మీరు క్లిష్టమైన పాస్వర్డ్లను క్రియేట్ చేయనవసరం లేదు లేదా గుర్తుంచుకోనవసరం లేదు"</string> <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"పాస్-కీలు అనేవి మీ వేలిముద్రను, ముఖాన్ని లేదా స్క్రీన్ లాక్ను ఉపయోగించి మీరు క్రియేట్ చేసే ఎన్క్రిప్ట్ చేసిన డిజిటల్ కీలు"</string> - <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"అవి Password Managerకు సేవ్ చేయబడతాయి, తద్వారా మీరు ఇతర పరికరాలలో సైన్ ఇన్ చేయవచ్చు"</string> + <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"ఏదైనా ఒక పాస్వర్డ్ మేనేజర్లో అవి సేవ్ అవుతాయి, తద్వారా మీరు ఇతర పరికరాలలో సైన్ ఇన్ చేయవచ్చు"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"పాస్-కీల గురించి మరిన్ని వివరాలు"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"పాస్వర్డ్ రహిత టెక్నాలజీ"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"పాస్వర్డ్లపై ఆధారపడకుండా సైన్ ఇన్ చేయడానికి పాస్-కీలు మిమ్మల్ని అనుమతిస్తాయి. మీ గుర్తింపును వెరిఫై చేసి, పాస్-కీని క్రియేట్ చేయడానికి మీరు మీ వేలిముద్ర, ముఖ గుర్తింపు, PIN, లేదా స్వైప్ ఆకృతిని ఉపయోగించాలి."</string> @@ -22,7 +22,7 @@ <string name="seamless_transition_title" msgid="5335622196351371961">"అవాంతరాలు లేని పరివర్తన"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"మనం భవిష్యత్తులో పాస్వర్డ్ రహిత టెక్నాలజీని ఉపయోగించినా, పాస్-కీలతో పాటు పాస్వర్డ్లు కూడా అందుబాటులో ఉంటాయి"</string> <string name="choose_provider_title" msgid="8870795677024868108">"మీ <xliff:g id="CREATETYPES">%1$s</xliff:g> ఎక్కడ సేవ్ చేయాలో ఎంచుకోండి"</string> - <string name="choose_provider_body" msgid="4967074531845147434">"మీ సమాచారాన్ని సేవ్ చేయడం కోసం ఒక Password Managerను ఎంచుకొని, తర్వాతిసారి వేగంగా సైన్ ఇన్ చేయండి"</string> + <string name="choose_provider_body" msgid="4967074531845147434">"తర్వాతిసారి మరింత వేగంగా సైన్ ఇన్ చేసేందుకు వీలుగా మీ సమాచారాన్ని సేవ్ చేయడం కోసం ఒక పాస్వర్డ్ మేనేజర్ను ఎంచుకోండి"</string> <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> కోసం పాస్-కీని క్రియేట్ చేయాలా?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> కోసం పాస్వర్డ్ను సేవ్ చేయాలా?"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> కోసం సైన్ ఇన్ సమాచారాన్ని సేవ్ చేయాలా?"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం మీ సేవ్ చేసిన పాస్-కీని ఉపయోగించాలా?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం మీరు సేవ్ చేసిన సైన్ ఇన్ వివరాలను ఉపయోగించాలా?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం సేవ్ చేసిన సైన్ ఇన్ వివరాలను ఎంచుకోండి"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"మరొక పద్ధతిలో సైన్ ఇన్ చేయండి"</string> <string name="snackbar_action" msgid="37373514216505085">"ఆప్షన్లను చూడండి"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"కొనసాగించండి"</string> @@ -64,4 +66,5 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"సైన్ ఇన్లను మేనేజ్ చేయండి"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"మరొక పరికరం నుండి"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"వేరే పరికరాన్ని ఉపయోగించండి"</string> + <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>, రిక్వెస్ట్ను రద్దు చేసింది"</string> </resources> diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml index 894befbe27ae..446d307e2a16 100644 --- a/packages/CredentialManager/res/values-th/strings.xml +++ b/packages/CredentialManager/res/values-th/strings.xml @@ -16,7 +16,7 @@ <string name="passwordless_technology_title" msgid="2497513482056606668">"เทคโนโลยีที่ไม่ต้องใช้รหัสผ่าน"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"พาสคีย์ช่วยให้คุณลงชื่อเข้าใช้ได้โดยไม่ต้องใช้รหัสผ่าน ใช้เพียงแค่ลายนิ้วมือ, การจดจำใบหน้า, PIN หรือรูปแบบการลากเส้นในการยืนยันตัวตนและสร้างพาสคีย์"</string> <string name="public_key_cryptography_title" msgid="6751970819265298039">"วิทยาการเข้ารหัสคีย์สาธารณะ"</string> - <string name="public_key_cryptography_detail" msgid="6937631710280562213">"พาสคีย์ใช้คู่คีย์การเข้ารหัสตามมาตรฐานของ FIDO Alliance (เช่น Google, Apple, Microsoft และอื่นๆ) และ W3C คู่คีย์สาธารณะและคีย์ส่วนตัวจะสร้างขึ้นสำหรับแอปหรือเว็บไซต์ที่ใช้งานคีย์ดังกล่าวต่างจากชื่อผู้ใช้และชุดอักขระที่ใช้เป็นรหัสผ่าน โดยระบบจะจัดเก็บคีย์ส่วนตัวไว้ในอุปกรณ์หรือเครื่องมือจัดการรหัสผ่านและใช้คีย์ดังกล่าวเพื่อยืนยันตัวตน ส่วนคีย์สาธารณะจะแชร์กับเซิร์ฟเวอร์ของแอปหรือเว็บไซต์ ลงทะเบียนและลงชื่อเข้าใช้ได้ทันทีด้วยคีย์ที่สอดคล้องกัน"</string> + <string name="public_key_cryptography_detail" msgid="6937631710280562213">"พาสคีย์ใช้คู่คีย์การเข้ารหัสตามมาตรฐานของ FIDO Alliance (เช่น Google, Apple, Microsoft และอื่นๆ) และ W3C คู่คีย์สาธารณะและคีย์ส่วนตัวจะสร้างขึ้นสำหรับแอปหรือเว็บไซต์ ซึ่งต่างจากชื่อผู้ใช้และชุดอักขระที่ใช้เป็นรหัสผ่าน โดยระบบจะจัดเก็บคีย์ส่วนตัวไว้อย่างปลอดภัยในอุปกรณ์หรือเครื่องมือจัดการรหัสผ่านและใช้คีย์ดังกล่าวเพื่อยืนยันตัวตน ส่วนคีย์สาธารณะจะแชร์กับเซิร์ฟเวอร์ของแอปหรือเว็บไซต์ คุณลงทะเบียนและลงชื่อเข้าใช้ได้ทันทีด้วยคีย์ที่สอดคล้องกัน"</string> <string name="improved_account_security_title" msgid="1069841917893513424">"ความปลอดภัยของบัญชีที่เพิ่มมากขึ้น"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"คีย์ที่สร้างขึ้นแต่ละคีย์จะลิงก์กับแอปหรือเว็บไซต์ที่ใช้งานคีย์ดังกล่าวเท่านั้น ดังนั้นจึงไม่มีการลงชื่อเข้าใช้แอปเว็บไซต์ที่เป็นการฉ้อโกงโดยไม่ตั้งใจเกิดขึ้น นอกจากนี้ เซิร์ฟเวอร์จะบันทึกเฉพาะคีย์สาธารณะ จึงทำให้แฮ็กได้ยากขึ้น"</string> <string name="seamless_transition_title" msgid="5335622196351371961">"การเปลี่ยนผ่านอย่างราบรื่น"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ใช้พาสคีย์ที่บันทึกไว้สำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g> ใช่ไหม"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ใช้การลงชื่อเข้าใช้ที่บันทึกไว้สำหรับ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ใช่ไหม"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"เลือกการลงชื่อเข้าใช้ที่บันทึกไว้สำหรับ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ลงชื่อเข้าใช้ด้วยวิธีอื่น"</string> <string name="snackbar_action" msgid="37373514216505085">"ดูตัวเลือก"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ต่อไป"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"จัดการการลงชื่อเข้าใช้"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"จากอุปกรณ์อื่น"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ใช้อุปกรณ์อื่น"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml index 27452d603a9b..e9c9ef592522 100644 --- a/packages/CredentialManager/res/values-tl/strings.xml +++ b/packages/CredentialManager/res/values-tl/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gamitin ang iyong naka-save na passkey para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gamitin ang iyong naka-save na sign-in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pumili ng naka-save na sign-in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Mag-sign in sa ibang paraan"</string> <string name="snackbar_action" msgid="37373514216505085">"Mga opsyon sa view"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Magpatuloy"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Pamahalaan ang mga sign-in"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Mula sa ibang device"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gumamit ng ibang device"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml index 9ef4fc3b559b..1398e8d79f3f 100644 --- a/packages/CredentialManager/res/values-tr/strings.xml +++ b/packages/CredentialManager/res/values-tr/strings.xml @@ -26,13 +26,13 @@ <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> için şifre anahtarı oluşturulsun mu?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> için şifre kaydedilsin mi?"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> için oturum açma bilgileri kaydedilsin mi?"</string> - <string name="passkey" msgid="632353688396759522">"Şifre anahtarının"</string> + <string name="passkey" msgid="632353688396759522">"Şifre anahtarı"</string> <string name="password" msgid="6738570945182936667">"şifre"</string> <string name="passkeys" msgid="5733880786866559847">"Şifre anahtarlarınızın"</string> <string name="passwords" msgid="5419394230391253816">"şifreler"</string> <string name="sign_ins" msgid="4710739369149469208">"oturum aç"</string> <string name="sign_in_info" msgid="2627704710674232328">"oturum açma bilgileri"</string> - <string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> kaydedileceği yeri seçin"</string> + <string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> nereye kaydedilsin?"</string> <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Başka bir cihazda şifre anahtarı oluşturulsun mu?"</string> <string name="use_provider_for_all_title" msgid="4201020195058980757">"Tüm oturum açma işlemlerinizde <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kullanılsın mı?"</string> <string name="use_provider_for_all_description" msgid="1998772715863958997">"<xliff:g id="USERNAME">%1$s</xliff:g> için bu şifre yöneticisi, şifrelerinizi ve şifre anahtarlarınızı saklayarak kolayca oturum açmanıza yardımcı olur"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı şifre anahtarınız kullanılsın mı?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı oturum açma bilgileriniz kullanılsın mı?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı oturum açma bilgilerini kullanın"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Başka bir yöntemle oturum aç"</string> <string name="snackbar_action" msgid="37373514216505085">"Seçenekleri göster"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Devam"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Oturum açma bilgilerini yönetin"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başka bir cihazdan"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Farklı bir cihaz kullan"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml index 3c0655607a23..c5c1c2c457bf 100644 --- a/packages/CredentialManager/res/values-uk/strings.xml +++ b/packages/CredentialManager/res/values-uk/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Використати збережений ключ доступу для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Використати збережені дані для входу для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Виберіть збережені дані для входу в додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Увійти іншим способом"</string> <string name="snackbar_action" msgid="37373514216505085">"Переглянути варіанти"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Продовжити"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Керування даними для входу"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншого пристрою"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Використовувати інший пристрій"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml index 34813efe4913..b1a3b0f4ff4d 100644 --- a/packages/CredentialManager/res/values-ur/strings.xml +++ b/packages/CredentialManager/res/values-ur/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اپنی محفوظ کردہ پاس کی استعمال کریں؟"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اپنے محفوظ کردہ سائن ان کو استعمال کریں؟"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے محفوظ کردہ سائن انز منتخب کریں"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"دوسرے طریقے سے سائن ان کریں"</string> <string name="snackbar_action" msgid="37373514216505085">"اختیارات دیکھیں"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"جاری رکھیں"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"سائن انز کا نظم کریں"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"دوسرے آلے سے"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ایک مختلف آلہ استعمال کریں"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml index 8605993cc5ce..b2425ebcb47a 100644 --- a/packages/CredentialManager/res/values-uz/strings.xml +++ b/packages/CredentialManager/res/values-uz/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan kalit ishlatilsinmi?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan maʼlumotlar ishlatilsinmi?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> hisob maʼlumotlarini tanlang"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Boshqa usul orqali kirish"</string> <string name="snackbar_action" msgid="37373514216505085">"Variantlarni ochish"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Davom etish"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Hisob maʼlumotlarini boshqarish"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Boshqa qurilmada"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Boshqa qurilmadan foydalanish"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml index ab0dd59d9846..f0f7a3b4a5db 100644 --- a/packages/CredentialManager/res/values-vi/strings.xml +++ b/packages/CredentialManager/res/values-vi/strings.xml @@ -15,7 +15,7 @@ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Xem thêm thông tin về mã xác thực"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"Công nghệ không dùng mật khẩu"</string> <string name="passwordless_technology_detail" msgid="6853928846532955882">"Mã xác thực cho phép bạn đăng nhập mà không cần dựa vào mật khẩu. Bạn chỉ cần dùng vân tay, tính năng nhận dạng khuôn mặt, mã PIN hoặc hình mở khoá để xác minh danh tính và tạo mã xác thực."</string> - <string name="public_key_cryptography_title" msgid="6751970819265298039">"Mật mã của khoá công khai"</string> + <string name="public_key_cryptography_title" msgid="6751970819265298039">"Mã hoá khoá công khai"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Dựa trên Liên minh FIDO (bao gồm Google, Apple, Microsoft, v.v.) và tiêu chuẩn W3C, mã xác thực sử dụng cặp khoá mã hoá. Khác với tên người dùng và chuỗi ký tự chúng tôi dùng cho mật khẩu, một cặp khoá riêng tư – công khai được tạo cho một ứng dụng hoặc trang web. Khoá riêng tư được lưu trữ an toàn trên thiết bị hoặc trình quản lý mật khẩu và xác nhận danh tính của bạn. Khoá công khai được chia sẻ với máy chủ ứng dụng hoặc trang web. Với khoá tương ứng, bạn có thể đăng ký và đăng nhập tức thì."</string> <string name="improved_account_security_title" msgid="1069841917893513424">"Cải thiện tính bảo mật của tài khoản"</string> <string name="improved_account_security_detail" msgid="9123750251551844860">"Mỗi khoá được liên kết riêng với ứng dụng hoặc trang web mà khoá đó được tạo. Vì vậy, bạn sẽ không bao giờ đăng nhập nhầm vào một ứng dụng hoặc trang web lừa đảo. Ngoài ra, với các máy chủ chỉ lưu giữ khoá công khai, việc xâm nhập càng khó hơn nhiều."</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Dùng mã xác thực bạn đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Dùng thông tin đăng nhập bạn đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Chọn thông tin đăng nhập đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Đăng nhập bằng cách khác"</string> <string name="snackbar_action" msgid="37373514216505085">"Xem các lựa chọn"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Tiếp tục"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Quản lý thông tin đăng nhập"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Từ một thiết bị khác"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Dùng thiết bị khác"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml index 22944b2303a5..aabc6decaa30 100644 --- a/packages/CredentialManager/res/values-zh-rCN/strings.xml +++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml @@ -10,7 +10,7 @@ <string name="content_description_hide_password" msgid="6841375971631767996">"隐藏密码"</string> <string name="passkey_creation_intro_title" msgid="4251037543787718844">"通行密钥可提高安全性"</string> <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"借助通行密钥,您无需创建或记住复杂的密码"</string> - <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"通行密钥是指您使用您的指纹、面孔或屏锁方式创建的加密数字钥匙"</string> + <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"通行密钥是指您使用自己的指纹、面孔或屏锁创建的加密数字钥匙"</string> <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"系统会将通行密钥保存到密码管理工具中,以便您在其他设备上登录"</string> <string name="more_about_passkeys_title" msgid="7797903098728837795">"详细了解通行密钥"</string> <string name="passwordless_technology_title" msgid="2497513482056606668">"无密码技术"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用您已保存的\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"通行密钥吗?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"将您已保存的登录信息用于<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"为<xliff:g id="APP_NAME">%1$s</xliff:g>选择已保存的登录信息"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"使用其他登录方式"</string> <string name="snackbar_action" msgid="37373514216505085">"查看选项"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"继续"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登录信息"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"通过另一台设备"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他设备"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml index 46f6badb8df8..c3419a47cd3f 100644 --- a/packages/CredentialManager/res/values-zh-rHK/strings.xml +++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密鑰嗎?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資料嗎?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"選擇已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資料"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"使用其他方式登入"</string> <string name="snackbar_action" msgid="37373514216505085">"查看選項"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"繼續"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登入資料"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml index 3a0bf80b5054..cd77bcb9b735 100644 --- a/packages/CredentialManager/res/values-zh-rTW/strings.xml +++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml @@ -18,7 +18,7 @@ <string name="public_key_cryptography_title" msgid="6751970819265298039">"公開金鑰密碼編譯"</string> <string name="public_key_cryptography_detail" msgid="6937631710280562213">"密碼金鑰根據 FIDO 聯盟 (包括 Google、Apple、Microsoft 等) 及 W3C 標準,使用加密編譯金鑰組。有別於傳統密碼,系統會針對應用程式或網站建立專屬的私密 - 公開金鑰組,因此你不再需要輸入使用者名稱和一串密碼字元。私密金鑰會安全地儲存在裝置或密碼管理工具中,並用來確認你的身分。公開金鑰會提供給應用程式或網站伺服器。只要有相對應的金鑰,就能立即註冊和登入。"</string> <string name="improved_account_security_title" msgid="1069841917893513424">"提升帳戶安全性"</string> - <string name="improved_account_security_detail" msgid="9123750251551844860">"系統會為應用程式或網站建立專屬的對應金鑰,因此你不會意外登入詐欺性的應用程式或網站。此外,伺服器上只存放公開金鑰,因此可大幅降低駭客入侵的風險。"</string> + <string name="improved_account_security_detail" msgid="9123750251551844860">"系統會為應用程式或網站建立專屬的對應金鑰,因此你不會意外登入詐騙應用程式或網站。此外,伺服器上只存放公開金鑰,可大幅降低駭客入侵的風險。"</string> <string name="seamless_transition_title" msgid="5335622196351371961">"流暢轉換"</string> <string name="seamless_transition_detail" msgid="3440478759491650823">"即使現在已邁入無密碼時代,密碼仍可與密碼金鑰並用"</string> <string name="choose_provider_title" msgid="8870795677024868108">"選擇要將<xliff:g id="CREATETYPES">%1$s</xliff:g>存在哪裡"</string> @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密碼金鑰嗎?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資訊嗎?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"選擇已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資訊"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"使用其他方式登入"</string> <string name="snackbar_action" msgid="37373514216505085">"查看選項"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"繼續"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登入資訊"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml index b834ec041bd4..2927282fdff1 100644 --- a/packages/CredentialManager/res/values-zu/strings.xml +++ b/packages/CredentialManager/res/values-zu/strings.xml @@ -52,6 +52,8 @@ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Sebenzisa ukhiye wakho wokungena olondoloziwe <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Sebenzisa ukungena kwakho ngemvume okulondoloziwe <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Khetha ukungena ngemvume okulondoloziwe kwakho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for get_dialog_title_choose_option_for (4976380044745029107) --> + <skip /> <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Ngena ngemvume ngenye indlela"</string> <string name="snackbar_action" msgid="37373514216505085">"Buka okungakhethwa kukho"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Qhubeka"</string> @@ -64,4 +66,6 @@ <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Phatha ukungena ngemvume"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kusukela kwenye idivayisi"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Sebenzisa idivayisi ehlukile"</string> + <!-- no translation found for request_cancelled_by (3735222326886267820) --> + <skip /> </resources> diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml index 1d069b69f061..e9b2e1041c22 100644 --- a/packages/CredentialManager/res/values/strings.xml +++ b/packages/CredentialManager/res/values/strings.xml @@ -42,7 +42,7 @@ <!-- Title for subsection of "Learn more about passkeys" screen about seamless transition. [CHAR LIMIT=80] --> <string name="seamless_transition_title">Seamless transition</string> <!-- Detail for subsection of "Learn more about passkeys" screen about seamless transition. [CHAR LIMIT=500] --> - <string name="seamless_transition_detail">As we move towards a passwordless future, passwords will still be available alongside passkeys</string> + <string name="seamless_transition_detail">As we move towards a passwordless future, passwords will still be available alongside passkeys.</string> <!-- This appears as the title of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] --> <string name="choose_provider_title">Choose where to save your <xliff:g id="createTypes" example="passkeys">%1$s</xliff:g></string> <!-- This appears as the description body of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] --> @@ -103,6 +103,10 @@ <string name="get_dialog_title_use_sign_in_for">Use your saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> <!-- This appears as the title of the dialog asking for user to make a choice from various previously saved credentials to sign in to the app. [CHAR LIMIT=200] --> <string name="get_dialog_title_choose_sign_in_for">Choose a saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string> + <!-- This appears as the title of the dialog asking for user to make a choice from various previously saved credentials to sign in to the app. [CHAR LIMIT=200] --> + <string name="get_dialog_title_choose_option_for">Choose an option for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> + <!-- This appears as the title of the dialog asking user to use a previously saved credentials to sign in to the app. [CHAR LIMIT=200] --> + <string name="get_dialog_title_use_info_on">Use this info on <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string> <!-- This is a label for a button that links the user to different sign-in methods . [CHAR LIMIT=80] --> <string name="get_dialog_use_saved_passkey_for">Sign in another way</string> <!-- This is a label for a button that links the user to different sign-in methods. [CHAR LIMIT=80] --> diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index b3d3b6dc66d0..783cf3b47344 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -102,7 +102,7 @@ private fun getServiceLabelAndIcon( ).toString() providerIcon = pkgInfo.applicationInfo.loadIcon(pm) } catch (e: PackageManager.NameNotFoundException) { - Log.e(Constants.LOG_TAG, "Provider info not found", e) + Log.e(Constants.LOG_TAG, "Provider package info not found", e) } } else { try { @@ -113,7 +113,23 @@ private fun getServiceLabelAndIcon( ).toString() providerIcon = si.loadIcon(pm) } catch (e: PackageManager.NameNotFoundException) { - Log.e(Constants.LOG_TAG, "Provider info not found", e) + Log.e(Constants.LOG_TAG, "Provider service info not found", e) + // Added for mdoc use case where the provider may not need to register a service and + // instead only relies on the registration api. + try { + val pkgInfo = pm.getPackageInfo( + component.packageName, + PackageManager.PackageInfoFlags.of(0) + ) + providerLabel = + pkgInfo.applicationInfo.loadSafeLabel( + pm, 0f, + TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM + ).toString() + providerIcon = pkgInfo.applicationInfo.loadIcon(pm) + } catch (e: PackageManager.NameNotFoundException) { + Log.e(Constants.LOG_TAG, "Provider package info not found", e) + } } } return if (providerLabel == null || providerIcon == null) { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt index 7b98049b51c0..ed4cc959543b 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt @@ -296,7 +296,11 @@ fun ProviderSelectionCard( } item { Divider(thickness = 24.dp, color = Color.Transparent) } - item { BodyMediumText(text = stringResource(R.string.choose_provider_body)) } + item { + Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) { + BodyMediumText(text = stringResource(R.string.choose_provider_body)) + } + } item { Divider(thickness = 16.dp, color = Color.Transparent) } item { CredentialContainerCard { @@ -444,8 +448,10 @@ fun MoreOptionsRowIntroCard( } item { Divider(thickness = 24.dp, color = Color.Transparent) } item { - BodyMediumText(text = stringResource( - R.string.use_provider_for_all_description, entryInfo.userProviderDisplayName)) + Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) { + BodyMediumText(text = stringResource( + R.string.use_provider_for_all_description, entryInfo.userProviderDisplayName)) + } } item { Divider(thickness = 24.dp, color = Color.Transparent) } item { @@ -626,25 +632,33 @@ fun MoreAboutPasskeysIntroCard( MoreAboutPasskeySectionHeader( text = stringResource(R.string.passwordless_technology_title) ) - BodyMediumText(text = stringResource(R.string.passwordless_technology_detail)) + Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) { + BodyMediumText(text = stringResource(R.string.passwordless_technology_detail)) + } } item { MoreAboutPasskeySectionHeader( text = stringResource(R.string.public_key_cryptography_title) ) - BodyMediumText(text = stringResource(R.string.public_key_cryptography_detail)) + Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) { + BodyMediumText(text = stringResource(R.string.public_key_cryptography_detail)) + } } item { MoreAboutPasskeySectionHeader( text = stringResource(R.string.improved_account_security_title) ) - BodyMediumText(text = stringResource(R.string.improved_account_security_detail)) + Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) { + BodyMediumText(text = stringResource(R.string.improved_account_security_detail)) + } } item { MoreAboutPasskeySectionHeader( text = stringResource(R.string.seamless_transition_title) ) - BodyMediumText(text = stringResource(R.string.seamless_transition_detail)) + Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) { + BodyMediumText(text = stringResource(R.string.seamless_transition_detail)) + } } } onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_MORE_ABOUT_PASSKEYS_INTRO) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt index 8b95b5e46aa1..57fefbe577b4 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt @@ -19,8 +19,33 @@ package com.android.credentialmanager.getflow import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.result.ActivityResult import androidx.activity.result.IntentSenderRequest +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.Divider import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.core.graphics.drawable.toBitmap +import com.android.compose.rememberSystemUiController import com.android.credentialmanager.CredentialSelectorViewModel +import com.android.credentialmanager.R +import com.android.credentialmanager.common.BaseEntry +import com.android.credentialmanager.common.ProviderActivityState +import com.android.credentialmanager.common.ui.ConfirmButton +import com.android.credentialmanager.common.ui.CredentialContainerCard +import com.android.credentialmanager.common.ui.CtaButtonRow +import com.android.credentialmanager.common.ui.HeadlineIcon +import com.android.credentialmanager.common.ui.HeadlineText +import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant +import com.android.credentialmanager.common.ui.ModalBottomSheet +import com.android.credentialmanager.common.ui.SheetContainerCard +import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor +import com.android.credentialmanager.logging.GetCredentialEvent +import com.android.internal.logging.UiEventLogger + @Composable fun GetGenericCredentialScreen( @@ -28,5 +53,122 @@ fun GetGenericCredentialScreen( getCredentialUiState: GetCredentialUiState, providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult> ) { - // TODO(b/274129098): Implement Screen for mDocs -}
\ No newline at end of file + val sysUiController = rememberSystemUiController() + setBottomSheetSystemBarsColor(sysUiController) + ModalBottomSheet( + sheetContent = { + when (viewModel.uiState.providerActivityState) { + ProviderActivityState.NOT_APPLICABLE -> { + PrimarySelectionCardGeneric( + requestDisplayInfo = getCredentialUiState.requestDisplayInfo, + providerDisplayInfo = getCredentialUiState.providerDisplayInfo, + providerInfoList = getCredentialUiState.providerInfoList, + onEntrySelected = viewModel::getFlowOnEntrySelected, + onConfirm = viewModel::getFlowOnConfirmEntrySelected, + onLog = { viewModel.logUiEvent(it) }, + ) + viewModel.uiMetrics.log(GetCredentialEvent + .CREDMAN_GET_CRED_SCREEN_PRIMARY_SELECTION) + } + ProviderActivityState.READY_TO_LAUNCH -> { + // Launch only once per providerActivityState change so that the provider + // UI will not be accidentally launched twice. + LaunchedEffect(viewModel.uiState.providerActivityState) { + viewModel.launchProviderUi(providerActivityLauncher) + } + viewModel.uiMetrics.log(GetCredentialEvent + .CREDMAN_GET_CRED_PROVIDER_ACTIVITY_READY_TO_LAUNCH) + } + ProviderActivityState.PENDING -> { + // Hide our content when the provider activity is active. + viewModel.uiMetrics.log(GetCredentialEvent + .CREDMAN_GET_CRED_PROVIDER_ACTIVITY_PENDING) + } + } + }, + onDismiss = viewModel::onUserCancel, + ) +} + +@Composable +fun PrimarySelectionCardGeneric( + requestDisplayInfo: RequestDisplayInfo, + providerDisplayInfo: ProviderDisplayInfo, + providerInfoList: List<ProviderInfo>, + onEntrySelected: (BaseEntry) -> Unit, + onConfirm: () -> Unit, + onLog: @Composable (UiEventLogger.UiEventEnum) -> Unit, +) { + val sortedUserNameToCredentialEntryList = + providerDisplayInfo.sortedUserNameToCredentialEntryList + val totalEntriesCount = sortedUserNameToCredentialEntryList + .flatMap { it.sortedCredentialEntryList }.size + SheetContainerCard { + // When only one provider (not counting the remote-only provider) exists, display that + // provider's icon + name up top. + if (providerInfoList.size <= 2) { // It's only possible to be the single provider case + // if we are started with no more than 2 providers. + val nonRemoteProviderList = providerInfoList.filter( + { it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() } + ) + if (nonRemoteProviderList.size == 1) { + val providerInfo = nonRemoteProviderList.firstOrNull() // First should always work + // but just to be safe. + if (providerInfo != null) { + item { + HeadlineIcon( + bitmap = providerInfo.icon.toBitmap().asImageBitmap(), + tint = Color.Unspecified, + ) + } + item { Divider(thickness = 4.dp, color = Color.Transparent) } + item { LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName) } + item { Divider(thickness = 16.dp, color = Color.Transparent) } + } + } + } + + item { + HeadlineText( + text = stringResource( + if (totalEntriesCount == 1) { + R.string.get_dialog_title_use_info_on + } else { + R.string.get_dialog_title_choose_option_for + }, + requestDisplayInfo.appName + ), + ) + } + item { Divider(thickness = 24.dp, color = Color.Transparent) } + item { + CredentialContainerCard { + Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { + sortedUserNameToCredentialEntryList.forEach { + // TODO(b/275375861): fallback UI merges entries by account names. + // Need a strategy to be able to show all entries. + CredentialEntryRow( + credentialEntryInfo = it.sortedCredentialEntryList.first(), + onEntrySelected = onEntrySelected, + enforceOneLine = true, + ) + } + } + } + } + item { Divider(thickness = 24.dp, color = Color.Transparent) } + item { + if (totalEntriesCount == 1) { + CtaButtonRow( + rightButton = { + ConfirmButton( + stringResource(R.string.get_dialog_button_label_continue), + onClick = onConfirm + ) + } + ) + } + } + } + onLog(GetCredentialEvent.CREDMAN_GET_CRED_PRIMARY_SELECTION_CARD) +} diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml index 5f0e3c2e69f4..267d63459a7c 100644 --- a/packages/PackageInstaller/res/values-af/strings.xml +++ b/packages/PackageInstaller/res/values-af/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Program geïnstalleer."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Wil jy hierdie program installeer?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Wil jy hierdie program opdateer?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Dateer hierdie app vanaf <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> op?\n\nHierdie app kry gewoonlik opdaterings vanaf <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. As jy vanaf ’n ander bron opdateer, kan jy in die toekoms dalk opdaterings vanaf enige bron op jou foon kry. Appfunksie kan verander."</string> <string name="install_failed" msgid="5777824004474125469">"Program nie geïnstalleer nie."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Die installering van die pakket is geblokkeer."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Program is nie geïnstalleer nie omdat pakket met \'n bestaande pakket bots."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Hierdie gebruiker kan nie onbekende programme installeer nie"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Hierdie gebruiker word nie toegelaat om programme te installeer nie"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Dateer in elk geval op"</string> <string name="manage_applications" msgid="5400164782453975580">"Bestuur programme"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Geen spasie oor nie"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> kon nie geïnstalleer word nie. Maak spasie beskikbaar en probeer weer."</string> diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml index e2a25b3b4baa..3dab467c4cf7 100644 --- a/packages/PackageInstaller/res/values-am/strings.xml +++ b/packages/PackageInstaller/res/values-am/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"መተግበሪያ ተጭኗል።"</string> <string name="install_confirm_question" msgid="7663733664476363311">"ይህን መተግበሪያ መጫን ይፈልጋሉ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ይህን መተግበሪያ ማዘመን ይፈልጋሉ?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ይህ መተግበሪያ ከ<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ይዘምን?\n\nይህ መተግበሪያ በመደበኛነት ዝማኔዎችን ከ<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ይቀበላል። ከተለየ ምንጭ በማዘመን በስልክዎ ላይ ካለ ማንኛውም ምንጭ የወደፊት ዝማኔዎችን ሊቀበሉ ይችላሉ። የመተግበሪያ ተግባራዊነት ሊለወጥ ይችላል።"</string> <string name="install_failed" msgid="5777824004474125469">"መተግበሪያ አልተጫነም።"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ጥቅሉ እንዳይጫን ታግዷል።"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"እንደ ጥቅል ያልተጫነ መተግበሪያ ከነባር ጥቅል ጋር ይጋጫል።"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ያልታወቁ መተግበሪያዎች በዚህ ተጠቃሚ ሊጫኑ አይችሉም"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ይህ ተጠቃሚ መተግበሪያዎችን እንዲጭን አልተፈቀደለትም"</string> <string name="ok" msgid="7871959885003339302">"እሺ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"የሆነው ሆኖ አዘምን"</string> <string name="manage_applications" msgid="5400164782453975580">"መተግበሪያዎችን ያቀናብሩ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ቦታ ሞልቷል"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን መጫን አልቻለም። የተወሰነ ቦታ ያስለቅቁና እንደገና ይሞክሩ።"</string> diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml index 5c974b0e8e3b..170c1fcb05ac 100644 --- a/packages/PackageInstaller/res/values-ar/strings.xml +++ b/packages/PackageInstaller/res/values-ar/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"تم تثبيت التطبيق."</string> <string name="install_confirm_question" msgid="7663733664476363311">"هل تريد تثبيت هذا التطبيق؟"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"هل تريد تحديث هذا التطبيق؟"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"هل تريد تحديث هذا التطبيق من خلال \"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>\"؟\n\nيتلقّى هذا التطبيق التحديثات عادةً من \"<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>\". من خلال إجراء التحديث من مصدر مختلف، قد تتلقّى تحديثات في المستقبل من أي مصدر على هاتفك. قد تتغير وظائف التطبيق."</string> <string name="install_failed" msgid="5777824004474125469">"التطبيق ليس مثبتًا."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"تم حظر تثبيت الحزمة."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"لم يتم تثبيت التطبيق لأن حزمة التثبيت تتعارض مع حزمة حالية."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"يتعذر على هذا المستخدم تثبيت التطبيقات غير المعروفة"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"غير مسموح لهذا المستخدم بتثبيت التطبيقات"</string> <string name="ok" msgid="7871959885003339302">"حسنًا"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"التحديث على أي حال"</string> <string name="manage_applications" msgid="5400164782453975580">"إدارة التطبيقات"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"نفدت مساحة التخزين"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"تعذر تثبيت <xliff:g id="APP_NAME">%1$s</xliff:g> الرجاء تحرير بعض المساحة والمحاولة مرة أخرى."</string> diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml index 5997f2da1d09..c37ed705f188 100644 --- a/packages/PackageInstaller/res/values-as/strings.xml +++ b/packages/PackageInstaller/res/values-as/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"এপ্ ইনষ্টল কৰা হ’ল।"</string> <string name="install_confirm_question" msgid="7663733664476363311">"আপুনি এই এপ্টো ইনষ্টল কৰিবলৈ বিচাৰেনে?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"আপুনি এই এপ্টো আপডে’ট কৰিবলৈ বিচাৰেনে?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"এই এপ্টো <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ৰ পৰা আপডে’ট কৰিবনে?\n\nএই এপ্টোৱে সাধাৰণতে <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ৰ পৰা আপডে’ট লাভ কৰে। অন্য এটা উৎসৰ পৰা আপডে’ট কৰি আপুনি যিকোনো উৎসৰ পৰা আপোনাৰ ফ’নত অনাগত আপডে’টসমূহ পাব পাৰে। এপৰ কাৰ্যক্ষমতা সলনি হ’ব পাৰে।"</string> <string name="install_failed" msgid="5777824004474125469">"এপ্ ইনষ্টল কৰা হোৱা নাই।"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"পেকেজটোৰ ইনষ্টল অৱৰোধ কৰা হৈছে।"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"এপ্টো ইনষ্টল কৰিব পৰা নগ\'ল কাৰণ ইয়াৰ সৈতে আগৰে পৰা থকা এটা পেকেজৰ সংঘাত হৈছে।"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"এই ব্যৱহাৰকাৰীয়ে অজ্ঞাত উৎসৰপৰা পোৱা এপসমূহ ইনষ্টল কৰিব নোৱাৰে"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"এই ব্যৱহাৰকাৰীজনৰ এপ্ ইনষ্টল কৰাৰ অনুমতি নাই"</string> <string name="ok" msgid="7871959885003339302">"ঠিক আছে"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"যিকোনো প্ৰকাৰে আপডে’ট কৰক"</string> <string name="manage_applications" msgid="5400164782453975580">"এপ্ পৰিচালনা"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"খালী ঠাই নাই"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ইনষ্টল কৰিব পৰা নগ\'ল। কিছু খালী ঠাই উলিয়াই আকৌ চেষ্টা কৰক৷"</string> diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml index 0fb5005f3d8c..ae7b2fcd6411 100644 --- a/packages/PackageInstaller/res/values-az/strings.xml +++ b/packages/PackageInstaller/res/values-az/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Tətbiq quraşdırılıb."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Bu tətbiqi quraşdırmaq istəyirsiniz?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Bu tətbiqi güncəlləmək istəyirsiniz?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Bu tətbiq <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> mənbəyindən güncəllənsin?\n\nBu tətbiq adətən <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> mənbəyindən güncəllənmələr qəbul edir. Fərqli mənbədən güncəllədikdə telefonda istənilən mənbədən gələcəkdə güncəllənmələr qəbul edə bilərsiniz. Tətbiq funksionallığı dəyişə bilər."</string> <string name="install_failed" msgid="5777824004474125469">"Tətbiq quraşdırılmayıb."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paketin quraşdırılması blok edildi."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Bu paketin mövcud paket ilə ziddiyətinə görə tətbiq quraşdırılmadı."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Naməlum tətbiqlər bu istifadəçi tərəfindən quraşdırıla bilməz"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Bu istifadəçinin tətbiqi quraşdırmaq üçün icazəsi yoxdur"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"İstənilən halda güncəlləyin"</string> <string name="manage_applications" msgid="5400164782453975580">"Tətbiqi idarə edin"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Boş yer yoxdur"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> quraşdırıla bilməz. Yaddaş üçün yer boşaldıb yenidən təkrar edin."</string> diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml index f89266ca2694..2b0fa823afef 100644 --- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml +++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Želite da instalirate ovu aplikaciju?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Želite da ažurirate ovu aplikaciju?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Želite da ažurirate ovu aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija se obično ažurira iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako ažurirate iz drugog izvora, možete da primate buduća ažuriranja iz bilo kog izvora na telefonu. Funkcije aplikacije mogu da se promene."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa je blokirano."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer je paket neusaglašen sa postojećim paketom."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ovaj korisnik ne može da instalira nepoznate aplikacije"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ovom korisniku nije dozvoljeno da instalira aplikacije"</string> <string name="ok" msgid="7871959885003339302">"Potvrdi"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Ipak ažuriraj"</string> <string name="manage_applications" msgid="5400164782453975580">"Upravljajte apl."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nema više prostora"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Nismo uspeli da instaliramo aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>. Oslobodite prostor i probajte ponovo."</string> diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml index 369a60c04b38..d18e009c88a4 100644 --- a/packages/PackageInstaller/res/values-be/strings.xml +++ b/packages/PackageInstaller/res/values-be/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Праграма ўсталявана."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Усталяваць гэту праграму?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Абнавіць гэту праграму?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Абнавіць праграму ад <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗвычайна гэтая праграма атрымлівае абнаўленні ад <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Пры абнаўленні з іншай крыніцы вы, магчыма, будзеце атрымліваць будучыя абнаўленні з любой крыніцы на тэлефоне. Функцыі праграмы могуць змяніцца."</string> <string name="install_failed" msgid="5777824004474125469">"Праграма не ўсталявана."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Усталяванне пакета заблакіравана."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Праграма не ўсталявана, таму што пакет канфліктуе з існуючым пакетам."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Гэты карыстальнік не можа ўсталёўваць невядомыя праграмы"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Гэты карыстальнік не можа ўсталёўваць праграмы"</string> <string name="ok" msgid="7871959885003339302">"ОК"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Усё роўна абнавіць"</string> <string name="manage_applications" msgid="5400164782453975580">"Кіраваць"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Не хапае месца"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Не ўдалося ўсталяваць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\". Вызваліце месца і паўтарыце спробу."</string> diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml index 8263fe13bab3..6dc927f7cd5c 100644 --- a/packages/PackageInstaller/res/values-bg/strings.xml +++ b/packages/PackageInstaller/res/values-bg/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Приложението бе инсталирано."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Искате ли да инсталирате това приложение?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Искате ли да актуализирате това приложение?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Да се актуализира ли това приложение от <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nТо обикновено получава актуализации от <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако инсталирате актуализация от друг източник, може да получавате бъдещи актуализации от който и да е източник на телефона си. Функционалността на приложението може да се промени."</string> <string name="install_failed" msgid="5777824004474125469">"Приложението не бе инсталирано."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирането на пакета бе блокирано."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Приложението не бе инсталирано, тъй като пакетът е в конфликт със съществуващ пакет."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Този потребител не може да инсталира неизвестни приложения"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Този потребител няма разрешение да инсталира приложения"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Актуализиране въпреки това"</string> <string name="manage_applications" msgid="5400164782453975580">"Прил.: Управл."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Няма място"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> не можа да се инсталира. Освободете място и опитайте отново."</string> diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml index 0d15a7e707e6..5b5c6dc7c8e9 100644 --- a/packages/PackageInstaller/res/values-bn/strings.xml +++ b/packages/PackageInstaller/res/values-bn/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"অ্যাপটি ইনস্টল করা হয়ে গেছে।"</string> <string name="install_confirm_question" msgid="7663733664476363311">"আপনি কি এই অ্যাপটি ইনস্টল করতে চান?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"আপনি কি এই অ্যাপটি আপডেট করতে চান?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> থেকে এই অ্যাপ আপডেট করবেন?\n\nএই অ্যাপ সাধারণত <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> থেকে আপডেট পায়। অন্য কোনও সোর্স থেকে আপডেট করলে, আপনার ফোনে ভবিষ্যতে যেকোনও সোর্স থেকে আপডেট পেতে পারেন। অ্যাপের কার্যকারিতা পরিবর্তন হতে পারে।"</string> <string name="install_failed" msgid="5777824004474125469">"অ্যাপটি ইনস্টল করা হয়নি।"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ইনস্টল হওয়া থেকে প্যাকেজটিকে ব্লক করা হয়েছে।"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"আগে থেকেই থাকা একটি প্যাকেজের সাথে প্যাকেজটির সমস্যা সৃষ্টি হওয়ায় অ্যাপটি ইনস্টল করা যায়নি।"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"এই ব্যবহারকারী অজানা অ্যাপ ইনস্টল করতে পারেন না"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"এই ব্যবহারকারীর অ্যাপ ইনস্টল করার অনুমতি নেই"</string> <string name="ok" msgid="7871959885003339302">"ঠিক আছে"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"তবুও আপডেট করতে চাই"</string> <string name="manage_applications" msgid="5400164782453975580">"অ্যাপ পরিচালনা"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"জায়গা খালি নেই"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ইনস্টল করা যায়নি। কিছু পরিমাণ জায়গা খালি করে আবার চেষ্টা করুন।"</string> diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml index 8b197694329e..e728937b348f 100644 --- a/packages/PackageInstaller/res/values-bs/strings.xml +++ b/packages/PackageInstaller/res/values-bs/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Ažurirati aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate iz drugog izvora, možda ćete primati buduća ažuriranja iz bilo kojeg izvora na telefonu. Funkcionalnost aplikacije se može promijeniti."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje ovog paketa je blokirano."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer paket nije usaglašen s postojećim paketom."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ovaj korisnik ne može instalirati nepoznate aplikacije"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ovom korisniku nije dozvoljeno instaliranje aplikacija"</string> <string name="ok" msgid="7871959885003339302">"Uredu"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Ipak ažuriraj"</string> <string name="manage_applications" msgid="5400164782453975580">"Uprav. aplik."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nedostatak prostora"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Ne možete instalirati aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>. Oslobodite prostor u pohrani i pokušajte ponovo."</string> diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml index d025b9a88108..79833756077b 100644 --- a/packages/PackageInstaller/res/values-ca/strings.xml +++ b/packages/PackageInstaller/res/values-ca/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"S\'ha instal·lat l\'aplicació."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vols instal·lar aquesta aplicació?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vols actualitzar aquesta aplicació?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vols actualitzar l\'aplicació de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAquesta aplicació sol rebre actualitzacions de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> Si l\'actualitzes des d\'una font diferent, pot ser que en el futur rebis actualitzacions des de qualsevol font del teu telèfon. És possible que la funcionalitat de l\'aplicació canviï."</string> <string name="install_failed" msgid="5777824004474125469">"No s\'ha instal·lat l\'aplicació."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"El paquet s\'ha bloquejat perquè no es pugui instal·lar."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"L\'aplicació no s\'ha instal·lat perquè el paquet entra en conflicte amb un d\'existent."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aquest usuari no pot instal·lar aplicacions desconegudes"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Aquest usuari no té permís per instal·lar aplicacions"</string> <string name="ok" msgid="7871959885003339302">"D\'acord"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Actualitza de tota manera"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestiona apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Espai esgotat"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"No s\'ha pogut instal·lar <xliff:g id="APP_NAME">%1$s</xliff:g>. Allibera espai i torna-ho a provar."</string> diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml index 5799e72a4aae..c96d27e05125 100644 --- a/packages/PackageInstaller/res/values-cs/strings.xml +++ b/packages/PackageInstaller/res/values-cs/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikace je nainstalována."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Chcete tuto aplikaci nainstalovat?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete tuto aplikaci aktualizovat?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Aktualizovat tuto aplikaci ze zdroje <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTato aplikace obvykle dostává aktualizace ze zdroje <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Pokud ji aktualizujete z jiného zdroje, budete v budoucnu do telefonu moci dostávat aktualizace z libovolného zdroje. Funkčnost aplikace se může změnit."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikaci nelze nainstalovat."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Instalace balíčku byla zablokována."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikaci nelze nainstalovat, protože balíček je v konfliktu se stávajícím balíčkem."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Tento uživatel nemůže instalovat neznámé aplikace"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Tento uživatel nesmí instalovat aplikace"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Přesto aktualizovat"</string> <string name="manage_applications" msgid="5400164782453975580">"Správa aplikací"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nedostatek místa"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g> nelze nainstalovat. Uvolněte místo v paměti a zkuste to znovu."</string> diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml index d312de2277ea..d8759d4b61f0 100644 --- a/packages/PackageInstaller/res/values-da/strings.xml +++ b/packages/PackageInstaller/res/values-da/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Appen er installeret."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du opdatere denne app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vil du opdatere denne app fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne app plejer at modtage opdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din telefon fremover. Appfunktionaliteten kan ændre sig."</string> <string name="install_failed" msgid="5777824004474125469">"Appen blev ikke installeret."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Pakken blev forhindret i at blive installeret."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Appen blev ikke installeret, da pakken er i strid med en eksisterende pakke."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Denne bruger kan ikke installere ukendte apps"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Denne bruger har ikke tilladelse til at installere apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Opdater alligevel"</string> <string name="manage_applications" msgid="5400164782453975580">"Administrer apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Der er ikke mere plads"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> kunne ikke installeres. Frigør noget plads, og prøv igen."</string> diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml index 8b092d75691e..9721a193b994 100644 --- a/packages/PackageInstaller/res/values-el/strings.xml +++ b/packages/PackageInstaller/res/values-el/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Η εφαρμογή εγκαταστάθηκε."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Θέλετε να εγκαταστήσετε αυτήν την εφαρμογή;"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Θέλετε να ενημερώσετε αυτήν την εφαρμογή;"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Να ενημερωθεί αυτή η εφαρμογή από <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>;\n\nΗ συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο τηλέφωνό σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει."</string> <string name="install_failed" msgid="5777824004474125469">"Η εφαρμογή δεν εγκαταστάθηκε."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Η εγκατάσταση του πακέτου αποκλείστηκε."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Η εφαρμογή δεν εγκαταστάθηκε, επειδή το πακέτο είναι σε διένεξη με κάποιο υπάρχον πακέτο."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Δεν είναι δυνατή η εγκατάσταση άγνωστων εφαρμογών από αυτόν τον χρήστη"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Δεν επιτρέπεται η εγκατάσταση εφαρμογών σε αυτόν τον χρήστη"</string> <string name="ok" msgid="7871959885003339302">"ΟΚ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Να ενημερωθεί ούτως ή άλλως"</string> <string name="manage_applications" msgid="5400164782453975580">"Διαχ. εφαρμογών"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Δεν υπάρχει χώρος"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Δεν ήταν δυνατή η εγκατάσταση της εφαρμογής <xliff:g id="APP_NAME">%1$s</xliff:g>. Απελευθερώστε λίγο χώρο και προσπαθήστε ξανά."</string> diff --git a/packages/PackageInstaller/res/values-en-rAU/strings.xml b/packages/PackageInstaller/res/values-en-rAU/strings.xml index bb05ec43fd40..543dbf6547b9 100644 --- a/packages/PackageInstaller/res/values-en-rAU/strings.xml +++ b/packages/PackageInstaller/res/values-en-rAU/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App installed."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string> <string name="install_failed" msgid="5777824004474125469">"App not installed."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Unknown apps can\'t be installed by this user"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"This user is not allowed to install apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Update anyway"</string> <string name="manage_applications" msgid="5400164782453975580">"Manage apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Out of space"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> couldn\'t be installed. Free up some space and try again."</string> diff --git a/packages/PackageInstaller/res/values-en-rGB/strings.xml b/packages/PackageInstaller/res/values-en-rGB/strings.xml index bb05ec43fd40..543dbf6547b9 100644 --- a/packages/PackageInstaller/res/values-en-rGB/strings.xml +++ b/packages/PackageInstaller/res/values-en-rGB/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App installed."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string> <string name="install_failed" msgid="5777824004474125469">"App not installed."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Unknown apps can\'t be installed by this user"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"This user is not allowed to install apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Update anyway"</string> <string name="manage_applications" msgid="5400164782453975580">"Manage apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Out of space"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> couldn\'t be installed. Free up some space and try again."</string> diff --git a/packages/PackageInstaller/res/values-en-rIN/strings.xml b/packages/PackageInstaller/res/values-en-rIN/strings.xml index bb05ec43fd40..543dbf6547b9 100644 --- a/packages/PackageInstaller/res/values-en-rIN/strings.xml +++ b/packages/PackageInstaller/res/values-en-rIN/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App installed."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string> <string name="install_failed" msgid="5777824004474125469">"App not installed."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Unknown apps can\'t be installed by this user"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"This user is not allowed to install apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Update anyway"</string> <string name="manage_applications" msgid="5400164782453975580">"Manage apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Out of space"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> couldn\'t be installed. Free up some space and try again."</string> diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml index 12812ae9b35d..53514fe6809a 100644 --- a/packages/PackageInstaller/res/values-es-rUS/strings.xml +++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Se instaló la app."</string> <string name="install_confirm_question" msgid="7663733664476363311">"¿Deseas instalar esta app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"¿Deseas actualizar esta app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"¿Quieres actualizar esta app a través <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEn general, esta suele recibir actualizaciones de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en el teléfono. Por ende, podría verse afectada la funcionalidad de la app."</string> <string name="install_failed" msgid="5777824004474125469">"No se instaló la app."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Se bloqueó el paquete para impedir la instalación."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"No se instaló la app debido a un conflicto con un paquete."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este usuario no puede instalar apps desconocidas"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuario no puede instalar apps"</string> <string name="ok" msgid="7871959885003339302">"Aceptar"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Actualizar de todas formas"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestionar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sin espacio"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"No se pudo instalar <xliff:g id="APP_NAME">%1$s</xliff:g>. Libera espacio y vuelve a intentarlo."</string> diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml index b6714d3bb515..efb73b4d5865 100644 --- a/packages/PackageInstaller/res/values-es/strings.xml +++ b/packages/PackageInstaller/res/values-es/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplicación instalada."</string> <string name="install_confirm_question" msgid="7663733664476363311">"¿Quieres instalar esta aplicación?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"¿Quieres actualizar esta aplicación?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"¿Actualizar esta aplicación con <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEsta aplicación suele recibir actualizaciones de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si actualizas a través de otra fuente, puede que recibas futuras actualizaciones de cualquier fuente de tu teléfono. La funcionalidad de la aplicación puede cambiar."</string> <string name="install_failed" msgid="5777824004474125469">"No se ha instalado la aplicación."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Se ha bloqueado la instalación del paquete."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"La aplicación no se ha instalado debido a un conflicto con un paquete."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este usuario no puede instalar aplicaciones desconocidas"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuario no tiene permiso para instalar aplicaciones"</string> <string name="ok" msgid="7871959885003339302">"Aceptar"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Actualizar igualmente"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestionar aplicaciones"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sin espacio"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"No se ha podido instalar <xliff:g id="APP_NAME">%1$s</xliff:g>. Libera espacio y vuelve a intentarlo."</string> diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml index c4a3d05fa15d..cf488a935cce 100644 --- a/packages/PackageInstaller/res/values-et/strings.xml +++ b/packages/PackageInstaller/res/values-et/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Rakendus on installitud."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Kas soovite selle rakenduse installida?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Kas soovite seda rakendust värskendada?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Kas värskendada seda rakendust allikast <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nSee rakendus saab tavaliselt värskendusi allikast <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Muust allikast värskendamise korral võite edaspidi saada telefonis värskendusi mis tahes allikast. Rakenduse funktsioonid võivad muutuda."</string> <string name="install_failed" msgid="5777824004474125469">"Rakendus pole installitud."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paketi installimine blokeeriti."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Rakendust ei installitud, kuna pakett on olemasoleva paketiga vastuolus."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"See kasutaja ei saa installida tundmatuid rakendusi"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Kasutajal ei ole lubatud rakendusi installida"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Värskenda ikkagi"</string> <string name="manage_applications" msgid="5400164782453975580">"Rakend. haldam."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Pole ruumi"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Rakendust <xliff:g id="APP_NAME">%1$s</xliff:g> ei saanud installida. Vabastage ruumi ja proovige uuesti."</string> diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml index 97339dcd9d62..9dadbed74177 100644 --- a/packages/PackageInstaller/res/values-eu/strings.xml +++ b/packages/PackageInstaller/res/values-eu/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Instalatu da aplikazioa."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Aplikazioa instalatu nahi duzu?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Aplikazioa eguneratu nahi duzu?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Aplikazioa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> zerbitzutik eguneratu nahi duzu?\n\nAplikazioak <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> zerbitzutik jaso ohi ditu eguneratzeak. Beste iturburu batetik eguneratuz gero, baliteke aurrerantzeko eguneratzeak telefonoko edozein iturburutatik jasotzea. Baliteke aplikazioaren funtzioak aldatzea."</string> <string name="install_failed" msgid="5777824004474125469">"Ez da instalatu aplikazioa."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paketea instalatzeko aukera blokeatu egin da."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Ez da instalatu aplikazioa, gatazka bat sortu delako lehendik dagoen pakete batekin."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Erabiltzaile honek ezin ditu instalatu aplikazio ezezagunak"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Erabiltzaile honek ez du baimenik aplikazioak instalatzeko"</string> <string name="ok" msgid="7871959885003339302">"Ados"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Eguneratu halere"</string> <string name="manage_applications" msgid="5400164782453975580">"Kudeatu aplikazioak"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Ez dago behar adina toki"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Ezin izan da instalatu <xliff:g id="APP_NAME">%1$s</xliff:g>. Egin toki pixka bat eta saiatu berriro."</string> diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml index 65b3241e1783..73b070d1dad0 100644 --- a/packages/PackageInstaller/res/values-fa/strings.xml +++ b/packages/PackageInstaller/res/values-fa/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"برنامه نصب شد."</string> <string name="install_confirm_question" msgid="7663733664476363311">"میخواهید این برنامه را نصب کنید؟"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"میخواهید این برنامه را بهروزرسانی کنید؟"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"این برنامه ازطریق <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> بهروز شود؟\n\nاین برنامه معمولاً بهروزرسانیها را از <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> دریافت میکند. با بهروزرسانی از منبعی متفاوت، ممکن است بهروزرسانیهای بعدی را از هر منبعی در تلفنتان دریافت کنید. قابلیتهای برنامه ممکن است تغییر کند."</string> <string name="install_failed" msgid="5777824004474125469">"برنامه نصب نشد."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"از نصب شدن بسته جلوگیری شد."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"برنامه نصب نشد چون بسته با بسته موجود تداخل دارد."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"این کاربر نمیتواند برنامههای ناشناس نصب کند"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"این کاربر مجاز به نصب برنامه نیست"</string> <string name="ok" msgid="7871959885003339302">"بسیار خوب"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"درهرصورت بهروز شود"</string> <string name="manage_applications" msgid="5400164782453975580">"مدیریت برنامهها"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"فضا کافی نیست"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> نصب نمیشود. مقداری از فضا را آزاد و دوباره امتحان کنید."</string> diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml index a4306ae79527..ee8910b46966 100644 --- a/packages/PackageInstaller/res/values-fi/strings.xml +++ b/packages/PackageInstaller/res/values-fi/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Sovellus on asennettu."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Haluatko asentaa tämän sovelluksen?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Haluatko päivittää tämän sovelluksen?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Voiko <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> päivittää sovelluksen?\n\nTämän sovelluksen päivitykset tarjoaa yleensä <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kun päivität uudesta lähteestä, tulevat päivitykset voivat tulla mistä tahansa puhelimella olevasta lähteestä. Sovelluksen toiminnot voivat muuttua."</string> <string name="install_failed" msgid="5777824004474125469">"Sovellusta ei asennettu."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paketin asennus estettiin."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Sovellusta ei asennettu, koska paketti on ristiriidassa nykyisen paketin kanssa."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Tämä käyttäjä ei voi asentaa tuntemattomia sovelluksia."</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Tämä käyttäjä ei voi asentaa sovelluksia."</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Päivitä silti"</string> <string name="manage_applications" msgid="5400164782453975580">"Sovellusvalinnat"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Tallennustila ei riitä"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Sovelluksen <xliff:g id="APP_NAME">%1$s</xliff:g> asentaminen epäonnistui. Vapauta tallennustilaa ja yritä uudelleen."</string> diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml index 24efdd70bc39..b971c3534e27 100644 --- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml +++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Application installée."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette application?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette application?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Mettre à jour cette application à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nCette application reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application peut en être modifié."</string> <string name="install_failed" msgid="5777824004474125469">"Application non installée."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du paquet a été bloquée."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le paquet entre en conflit avec un paquet existant."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Cet utilisateur ne peut pas installer d\'applications inconnues"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Cet utilisateur n\'est pas autorisé à installer des applications"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Mettre à jour malgré tout"</string> <string name="manage_applications" msgid="5400164782453975580">"Gérer les applis"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Espace insuffisant"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Impossible d\'installer <xliff:g id="APP_NAME">%1$s</xliff:g>. Veuillez libérer de l\'espace, puis réessayer."</string> diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml index f3afb9012443..08d37d182d14 100644 --- a/packages/PackageInstaller/res/values-fr/strings.xml +++ b/packages/PackageInstaller/res/values-fr/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Application installée."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette appli ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette appli ?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Mettre à jour cette appli à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ?\n\nCette appli reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application est susceptible de changer."</string> <string name="install_failed" msgid="5777824004474125469">"Application non installée."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du package a été bloquée."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le package est en conflit avec un package déjà présent."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Cet utilisateur ne peut pas installer d\'applications inconnues"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Cet utilisateur n\'est pas autorisé à installer des applications"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Mettre à jour quand même"</string> <string name="manage_applications" msgid="5400164782453975580">"Gérer applis"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Mémoire insuffisante"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Impossible d\'installer l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>. Veuillez libérer de l\'espace et réessayer."</string> diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml index 5763bf17071d..d6cbf60c80c6 100644 --- a/packages/PackageInstaller/res/values-gl/strings.xml +++ b/packages/PackageInstaller/res/values-gl/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Instalouse a aplicación."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Queres instalar esta aplicación?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Queres actualizar esta aplicación?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Queres actualizar esta aplicación desde <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAs actualizacións desta aplicación adoitan provir de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se actualizas a aplicación desde unha fonte diferente, pode que, a partir de agora, recibas actualizacións de calquera fonte no teléfono. Poderían cambiar as funcións da aplicación."</string> <string name="install_failed" msgid="5777824004474125469">"Non se instalou a aplicación"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Bloqueouse a instalación do paquete."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"A aplicación non se instalou porque o paquete presenta un conflito cun paquete que xa hai."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este usuario non pode instalar aplicacións descoñecidas"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuario non ten permiso para instalar aplicacións"</string> <string name="ok" msgid="7871959885003339302">"Aceptar"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Actualizar de todas formas"</string> <string name="manage_applications" msgid="5400164782453975580">"Xestionar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Esgotouse o espazo"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Non se puido instalar a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>. Libera espazo e téntao de novo."</string> diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml index b3160e24dd3f..dcaa48f68c15 100644 --- a/packages/PackageInstaller/res/values-gu/strings.xml +++ b/packages/PackageInstaller/res/values-gu/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી."</string> <string name="install_confirm_question" msgid="7663733664476363311">"શું તમે આ ઍપ ઇન્સ્ટૉલ કરવા માગો છો?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"શું તમે આ ઍપ અપડેટ કરવા માગો છો?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"આ ઍપને <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>થી અપડેટ કરવી છે?\n\nઆ ઍપ સામાન્ય રીતે <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>થી અપડેટ મેળવે છે. અલગ સૉર્સથી અપડેટ કરીને, તમે તમારા ફોન પર કોઈપણ સૉર્સથી ભાવિ અપડેટ મેળવી શકો છો. ઍપની કાર્યક્ષમતા બદલાઈ શકે છે."</string> <string name="install_failed" msgid="5777824004474125469">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી નથી."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"પૅકેજને ઇન્સ્ટૉલ થવાથી બ્લૉક કરવામાં આવ્યું હતું."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"પૅકેજનો અસ્તિત્વમાંના પૅકેજ સાથે વિરોધાભાસ હોવાને કારણે ઍપ્લિકેશન ઇન્સ્ટૉલ થઈ નથી."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"આ વપરાશકર્તા અજાણી ઍપ્લિકેશનોને ઇન્સ્ટૉલ કરી શકતા નથી"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"આ વપરાશકર્તાને ઍપ્લિકેશનો ઇન્સ્ટૉલ કરવાની મંજૂરી નથી"</string> <string name="ok" msgid="7871959885003339302">"ઓકે"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"તો પણ અપડેટ કરો"</string> <string name="manage_applications" msgid="5400164782453975580">"ઍપને મેનેજ કરો"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"સ્પેસ નથી"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ઇન્સ્ટૉલ કરી શકાઈ નથી. થોડું સ્પેસ ખાલી કરો અને ફરીથી પ્રયાસ કરો."</string> diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml index 2372754cc9d8..2d79d1e703b4 100644 --- a/packages/PackageInstaller/res/values-hr/strings.xml +++ b/packages/PackageInstaller/res/values-hr/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Želite li ažurirati ovu aplikaciju s izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja s izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate s nekog drugog izvora, buduća ažuriranja možete primati s bilo kojeg izvora na svojem telefonu. Funkcije aplikacije mogu se promijeniti."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa blokirano je."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija koja nije instalirana kao paket u sukobu je s postojećim paketom."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ovaj korisnik ne može instalirati nepoznate aplikacije"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ovaj korisnik nema dopuštenje za instaliranje aplikacija"</string> <string name="ok" msgid="7871959885003339302">"U redu"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Ipak ažuriraj"</string> <string name="manage_applications" msgid="5400164782453975580">"Upravljanje apl."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nema dovoljno mjesta"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g> nije moguće instalirati. Oslobodite dio prostora i pokušajte ponovo."</string> diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml index 0ede377a6090..98072efc5d24 100644 --- a/packages/PackageInstaller/res/values-hu/strings.xml +++ b/packages/PackageInstaller/res/values-hu/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Alkalmazás telepítve."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Telepíti ezt az alkalmazást?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Frissíti ezt az alkalmazást?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"A(z) <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> forrásból rissíti ezt az appot?\n\nEz az app általában a következő forrásból kap frissítéseket: <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ha másik forrásból frissíti, a későbbiekben bármelyik forrásból kaphat frissítéseket a telefonján. Emiatt megváltozhat az app működése."</string> <string name="install_failed" msgid="5777824004474125469">"Az alkalmazás nincs telepítve."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"A csomag telepítését letiltotta a rendszer."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"A nem csomagként telepített alkalmazás ütközik egy már létező csomaggal."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ez a felhasználó nem telepíthet ismeretlen alkalmazásokat"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ez a felhasználó nem telepíthet alkalmazásokat"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Frissítés mindenképp"</string> <string name="manage_applications" msgid="5400164782453975580">"Alkalmazáskezelés"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nincs elég hely"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazást nem lehet telepíteni. Szabadítson fel egy kis helyet, és próbálkozzon újra."</string> diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml index ccf1ee47d040..4f5656829b47 100644 --- a/packages/PackageInstaller/res/values-hy/strings.xml +++ b/packages/PackageInstaller/res/values-hy/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Հավելվածը տեղադրված է:"</string> <string name="install_confirm_question" msgid="7663733664476363311">"Տեղադրե՞լ այս հավելվածը:"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Թարմացնե՞լ այս հավելվածը։"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Թարմացնե՞լ այս հավելվածը <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ից։\n\nՍովորաբար այս հավելվածի թարմացումները ստացվում են <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ից։ Եթե թարմացնեք այլ աղբյուրից, հետագայում կարող եք ձեր հեռախոսում թարմացումներ ստանալ ցանկացած աղբյուրից։ Հավելվածի գործառույթները կարող են փոփոխվել։"</string> <string name="install_failed" msgid="5777824004474125469">"Հավելվածը տեղադրված չէ:"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Փաթեթի տեղադրումն արգելափակվել է:"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Հավելվածը չի տեղադրվել, քանի որ տեղադրման փաթեթն ունի հակասություն առկա փաթեթի հետ:"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Այս օգտատերը չի կարող անհայտ հավելվածներ տեղադրել"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Այս օգտատիրոջը չի թույլատրվում տեղադրել հավելվածներ"</string> <string name="ok" msgid="7871959885003339302">"Եղավ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Թարմացնել"</string> <string name="manage_applications" msgid="5400164782453975580">"Կառավարել հավելվածները"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Բավարար տարածք չկա"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Չհաջողվեց տեղադրել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը: Ազատեք տարածք և նորից փորձեք:"</string> diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml index 0e4d700643b2..0758a1d1b550 100644 --- a/packages/PackageInstaller/res/values-in/strings.xml +++ b/packages/PackageInstaller/res/values-in/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikasi terinstal."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Ingin menginstal aplikasi ini?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Ingin mengupdate aplikasi ini?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update aplikasi ini dari <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAplikasi ini biasanya menerima update dari <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan mengupdate dari sumber yang berbeda, Anda mungkin menerima update berikutnya dari sumber mana pun di ponsel. Fungsi aplikasi mungkin berubah."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak terinstal."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paket diblokir sehingga tidak dapat diinstal."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikasi tidak diinstal karena paket ini bentrok dengan paket yang sudah ada."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aplikasi yang tidak dikenal tidak dapat diinstal oleh pengguna ini"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Pengguna ini tidak diizinkan menginstal aplikasi"</string> <string name="ok" msgid="7871959885003339302">"Oke"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Tetap update"</string> <string name="manage_applications" msgid="5400164782453975580">"Kelola aplikasi"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Kehabisan ruang penyimpanan"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak dapat diinstal. Kosongkan sebagian ruang dan coba lagi."</string> diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml index 64086c8d5702..6cbb2ee7be84 100644 --- a/packages/PackageInstaller/res/values-is/strings.xml +++ b/packages/PackageInstaller/res/values-is/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Forritið er uppsett."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Viltu setja upp þetta forrit?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Viltu uppfæra þetta forrit?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Uppfæra þetta forrit frá <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nÞetta forrit fær venjulega uppfærslur frá <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Með því að uppfæra frá öðrum uppruna gætirðu fengið framtíðaruppfærslur frá hvaða uppruna sem er í símanum. Forritseiginleikar kunna að breytast."</string> <string name="install_failed" msgid="5777824004474125469">"Forritið er ekki uppsett."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Lokað var á uppsetningu pakkans."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Forritið var ekki sett upp vegna árekstra á milli pakkans og annars pakka."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Þessi notandi getur ekki sett upp óþekkt forrit"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Þessi notandi hefur ekki leyfi til að setja upp forrit"</string> <string name="ok" msgid="7871959885003339302">"Í lagi"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Uppfæra samt"</string> <string name="manage_applications" msgid="5400164782453975580">"Stj. forritum"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Ekkert pláss eftir"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Ekki tókst að setja <xliff:g id="APP_NAME">%1$s</xliff:g> upp. Losaðu um pláss og reyndu aftur."</string> diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml index 617bfda063a5..e635313edc36 100644 --- a/packages/PackageInstaller/res/values-it/strings.xml +++ b/packages/PackageInstaller/res/values-it/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App installata."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vuoi installare questa app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vuoi aggiornare questa app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vuoi aggiornare questa app da <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nGeneralmente l\'app riceve gli aggiornamenti da <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se la aggiorni da un\'origine diversa, in futuro potresti ricevere gli aggiornamenti da qualsiasi origine sul telefono. La funzionalità dell\'app potrebbe cambiare."</string> <string name="install_failed" msgid="5777824004474125469">"App non installata."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"È stata bloccata l\'installazione del pacchetto."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"App non installata poiché il pacchetto è in conflitto con un pacchetto esistente."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Questo utente non può installare app sconosciute"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"L\'utente non è autorizzato a installare app"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Aggiorna comunque"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestisci app"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Spazio esaurito"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Impossibile installare <xliff:g id="APP_NAME">%1$s</xliff:g>. Libera dello spazio e riprova."</string> diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml index 226121832dbe..cf098ac67f21 100644 --- a/packages/PackageInstaller/res/values-iw/strings.xml +++ b/packages/PackageInstaller/res/values-iw/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"האפליקציה הותקנה."</string> <string name="install_confirm_question" msgid="7663733664476363311">"האם ברצונך להתקין אפליקציה זו?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"האם ברצונך לעדכן אפליקציה זו?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"לקבל את העדכון לאפליקציה הזו מ-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nהאפליקציה הזו בדרך כלל מקבלת עדכונים מ-<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. אם בחרת לעדכן ממקור אחר, יכול להיות שבעתיד יתקבלו עדכונים ממקורות אחרים בטלפון. תכונות האפליקציה יכולות להשתנות."</string> <string name="install_failed" msgid="5777824004474125469">"האפליקציה לא הותקנה."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"החבילה נחסמה להתקנה."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"האפליקציה לא הותקנה כי החבילה מתנגשת עם חבילה קיימת."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"למשתמש הזה אין הרשאה להתקין אפליקציות שאינן מוכרות"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"למשתמש הזה אין הרשאה להתקין אפליקציות"</string> <string name="ok" msgid="7871959885003339302">"אישור"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"אני רוצה לעדכן בכל זאת"</string> <string name="manage_applications" msgid="5400164782453975580">"ניהול אפליקציות"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"אין מספיק מקום"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"לא ניתן להתקין את <xliff:g id="APP_NAME">%1$s</xliff:g>. יש לפנות מקום אחסון ולנסות שוב."</string> diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml index 9764f1b9ddab..3e7a6c817c61 100644 --- a/packages/PackageInstaller/res/values-ja/strings.xml +++ b/packages/PackageInstaller/res/values-ja/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"アプリをインストールしました。"</string> <string name="install_confirm_question" msgid="7663733664476363311">"このアプリをインストールしますか?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"このアプリを更新しますか?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"このアプリを <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> から更新しますか?\n\nこのアプリは通常、<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> からアップデートを受信しています。別の提供元から更新することにより、お使いのスマートフォンで今後のアップデートを任意の提供元から受け取ることになります。アプリの機能は変更される場合があります。"</string> <string name="install_failed" msgid="5777824004474125469">"アプリはインストールされていません。"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"パッケージのインストールはブロックされています。"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"パッケージが既存のパッケージと競合するため、アプリをインストールできませんでした。"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"このユーザーは不明なアプリをインストールできません"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"このユーザーはアプリをインストールできません"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"更新する"</string> <string name="manage_applications" msgid="5400164782453975580">"アプリの管理"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"容量不足"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> をインストールできませんでした。空き容量を増やしてもう一度お試しください。"</string> diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml index ee0cefaadcf4..0699f0bd8973 100644 --- a/packages/PackageInstaller/res/values-ka/strings.xml +++ b/packages/PackageInstaller/res/values-ka/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"აპი დაინსტალირებულია."</string> <string name="install_confirm_question" msgid="7663733664476363311">"გნებავთ ამ აპის დაყენება?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"გსურთ ამ აპის განახლება?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"გსურთ განაახლოთ ეს აპი <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ისგან?\n\nეს აპი, როგორც წესი, განახლებებს იღებს <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ისგან. აპის სხვა წყაროდან განახლებით შემდგომში განახლებების მიღებას შეძლებთ ნებისმიერი წყაროდან თქვენს ტელეფონზე. აპის ფუნქციები, შესაძლოა, შეიცვალოს."</string> <string name="install_failed" msgid="5777824004474125469">"აპი დაუინსტალირებელია."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ამ პაკეტის ინსტალაცია დაბლოკილია."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"აპი ვერ დაინსტალირდა, რადგან პაკეტი კონფლიქტშია არსებულ პაკეტთან."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ამ მომხმარებელს არ შეუძლია უცნობი აპების ინსტალაცია"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ამ მომხმარებელს არ აქვს აპების ინსტალაციის უფლება"</string> <string name="ok" msgid="7871959885003339302">"კარგი"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"მაინც განახლდეს"</string> <string name="manage_applications" msgid="5400164782453975580">"აპების მართვა"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"მეხსიერება არასაკმარისია"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ვერ დაინსტალირდა. გაათავისუფლეთ მეხსიერება და ცადეთ ხელახლა."</string> diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml index 27b0289a3631..371aca3ea091 100644 --- a/packages/PackageInstaller/res/values-kk/strings.xml +++ b/packages/PackageInstaller/res/values-kk/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Қолданба орнатылды."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Бұл қолданбаны орнатқыңыз келе ме?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Бұл қолданбаны жаңартқыңыз келе ме?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Бұл қолданба <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> арқылы жаңартылсын ба?\n\nБұл қолданба әдетте <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> көмегімен жаңартылады. Басқа дереккөзден жаңартсаңыз, телефоныңыздағы кез келген дереккөзден алдағы жаңартулар берілуі мүмкін. Қолданба функциялары өзгеруі мүмкін."</string> <string name="install_failed" msgid="5777824004474125469">"Қолданба орнатылмады."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Пакетті орнатуға тыйым салынды."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Жаңа пакет пен бұрыннан бар пакеттің арасында қайшылық туындағандықтан, қолданба орнатылмады."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Бұл пайдаланушы белгісіз қолданбаларды орната алмайды"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Бұл пайдаланушының қолданбаларды орнату рұқсаты жоқ"</string> <string name="ok" msgid="7871959885003339302">"Жарайды"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Бәрібір жаңарту"</string> <string name="manage_applications" msgid="5400164782453975580">"Қолданбаларды басқару"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Орын жоқ"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы орнатылмады. Орын босатып, қайталап көріңіз."</string> diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml index 126218177bf4..04dc5749bab0 100644 --- a/packages/PackageInstaller/res/values-km/strings.xml +++ b/packages/PackageInstaller/res/values-km/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"បានដំឡើងកម្មវិធី។"</string> <string name="install_confirm_question" msgid="7663733664476363311">"តើអ្នកចង់ដំឡើងកម្មវិធីនេះដែរទេ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"តើអ្នកចង់ដំឡើងកំណែកម្មវិធីនេះដែរទេ?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ដំឡើងកំណែកម្មវិធីនេះពី <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ឬ?\n\nកម្មវិធីនេះជាធម្មតាទទួលបានកំណែថ្មីពី <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>។ តាមរយៈការដំឡើងកំណែពីប្រភពផ្សេង អ្នកអាចនឹងទទួលបានកំណែថ្មីនាពេលអនាគតពីប្រភពណាក៏បាននៅលើទូរសព្ទរបស់អ្នក។ មុខងារកម្មវិធីអាចមានការផ្លាស់ប្ដូរ។"</string> <string name="install_failed" msgid="5777824004474125469">"មិនបានដំឡើងកម្មវិធីទេ។"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"កញ្ចប់ត្រូវបានទប់ស្កាត់មិនឱ្យដំឡើង។"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"កម្មវិធីមិនបានដំឡើងទេ ដោយសារកញ្ចប់កម្មវិធីមិនត្រូវគ្នាជាមួយកញ្ចប់ដែលមានស្រាប់។"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"អ្នកប្រើប្រាស់នេះមិនអាចដំឡើងកម្មវិធីមិនស្គាល់បានទេ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"មិនអនុញ្ញាតឱ្យអ្នកប្រើប្រាស់នេះដំឡើងកម្មវិធីទេ"</string> <string name="ok" msgid="7871959885003339302">"យល់ព្រម"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"មិនអីទេ ដំឡើងកំណែចុះ"</string> <string name="manage_applications" msgid="5400164782453975580">"គ្រប់គ្រងកម្មវិធី"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"អស់ទំហំផ្ទុក"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"មិនអាចដំឡើង <xliff:g id="APP_NAME">%1$s</xliff:g> បានទេ។ សូមបង្កើនទំហំផ្ទុកទំនេរមួយចំនួន រួចព្យាយាមម្ដងទៀត។"</string> diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml index 43aaab1e7c94..037871264847 100644 --- a/packages/PackageInstaller/res/values-kn/strings.xml +++ b/packages/PackageInstaller/res/values-kn/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ."</string> <string name="install_confirm_question" msgid="7663733664476363311">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬೇಕೇ?\n\nಈ ಆ್ಯಪ್ ಸಾಮಾನ್ಯವಾಗಿ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ನಿಂದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ಸ್ವೀಕರಿಸುತ್ತದೆ. ಬೇರೆ ಮೂಲವೊಂದರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡುವ ಮೂಲಕ, ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿರುವ ಯಾವುದೇ ಮೂಲದಿಂದ ಭವಿಷ್ಯದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ನೀವು ಸ್ವೀಕರಿಸಬಹುದು. ಆ್ಯಪ್ನ ಕಾರ್ಯಚಟುವಟಿಕೆಯು ಬದಲಾಗಬಹುದು."</string> <string name="install_failed" msgid="5777824004474125469">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿಲ್ಲ."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡುವ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ಪ್ಯಾಕೇಜ್ನಂತೆ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿರುವ ಆ್ಯಪ್ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ಯಾಕೇಜ್ ಜೊತೆಗೆ ಸಂಘರ್ಷವಾಗುತ್ತದೆ."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ಈ ಬಳಕೆದಾರರು ಅಪರಿಚಿತ ಆ್ಯಪ್ಗಳನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ಆ್ಯಪ್ಗಳನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಈ ಬಳಕೆದಾರರನ್ನು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string> <string name="ok" msgid="7871959885003339302">"ಸರಿ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"ಪರವಾಗಿಲ್ಲ, ಅಪ್ಡೇಟ್ ಮಾಡಿ"</string> <string name="manage_applications" msgid="5400164782453975580">"ಆ್ಯಪ್ ನಿರ್ವಹಿಸಿ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ಸಂಗ್ರಹಣೆ ಖಾಲಿ ಇಲ್ಲ"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ಕೊಂಚ ಸ್ಥಳವನ್ನು ಖಾಲಿ ಮಾಡಿ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml index 9da1182fad43..06ce09594247 100644 --- a/packages/PackageInstaller/res/values-ko/strings.xml +++ b/packages/PackageInstaller/res/values-ko/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"앱이 설치되었습니다."</string> <string name="install_confirm_question" msgid="7663733664476363311">"이 앱을 설치하시겠습니까?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"이 앱을 업데이트하시겠습니까?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>에서 이 앱을 업데이트하시겠습니까?\n\n평소에는 <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>에서 앱을 업데이트했습니다. 다른 출처에서 업데이트를 받으면 향후 휴대전화에 있는 어떤 출처든지 업데이트를 받을 수 있습니다. 앱 기능도 변경될 수 있습니다."</string> <string name="install_failed" msgid="5777824004474125469">"앱이 설치되지 않았습니다."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"패키지 설치가 차단되었습니다."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"패키지가 기존 패키지와 충돌하여 앱이 설치되지 않았습니다."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"이 사용자는 알 수 없는 앱을 설치할 수 없습니다."</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"이 사용자는 앱을 설치할 권한이 없습니다."</string> <string name="ok" msgid="7871959885003339302">"확인"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"업데이트"</string> <string name="manage_applications" msgid="5400164782453975580">"앱 관리"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"여유 공간이 없음"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 설치할 수 없습니다. 여유 공간을 늘린 후에 다시 시도하세요."</string> diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml index 00a32f4b782d..c37775c2412a 100644 --- a/packages/PackageInstaller/res/values-ky/strings.xml +++ b/packages/PackageInstaller/res/values-ky/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Колдонмо орнотулду."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Бул колдонмону орнотоюн деп жатасызбы?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Бул колдонмону жаңыртайын деп жатасызбы?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Колдонмо <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> аркылуу жаңыртылсынбы?\n\nАдатта бул колдонмо <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> жөнөткөн жаңыртууларды алат. Башка булактан жаңыртуу менен келечекте телефонуңуз ар кайсы булактардан жаңыртылып калат. Колдонмонун функциялары өзгөрүшү мүмкүн."</string> <string name="install_failed" msgid="5777824004474125469">"Колдонмо орнотулган жок."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Топтомду орнотууга болбойт."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Башка топтом менен дал келбегендиктен колдонмо орнотулган жок."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Бул колдонуучу белгисиз колдонмолорду орното албайт"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Бул колдонуучу колдонмолорду орното албайт"</string> <string name="ok" msgid="7871959885003339302">"ЖАРАЙТ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Баары бир жаңыртылсын"</string> <string name="manage_applications" msgid="5400164782453975580">"Колд. башкаруу"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Бош орун жок"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосун телефонуңузга орнотуу мүмкүн эмес. Орун бошотуп, кайталап орнотуп көрүңүз."</string> diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml index 3cce796b3516..f3912cce919b 100644 --- a/packages/PackageInstaller/res/values-lo/strings.xml +++ b/packages/PackageInstaller/res/values-lo/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ຕິດຕັ້ງແອັບແລ້ວ."</string> <string name="install_confirm_question" msgid="7663733664476363311">"ທ່ານຕ້ອງການຕິດຕັ້ງແອັບນີ້ບໍ່?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ທ່ານຕ້ອງການອັບເດດແອັບນີ້ບໍ່?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ອັບເດດແອັບນີ້ຈາກ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ບໍ?\n\nໂດຍທົ່ວໄປແລ້ວແອັບນີ້ຈະໄດ້ຮັບການອັບເດດຈາກ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. ການອັບເດດຈາກແຫຼ່ງທີ່ມາອື່ນອາດເຮັດໃຫ້ໂທລະສັບຂອງທ່ານໄດ້ຮັບການອັບເດດຈາກແຫຼ່ງທີ່ມານັ້ນໃນອະນາຄົດ. ຟັງຊັນການເຮັດວຽກຂອງແອັບອາດມີການປ່ຽນແປງ."</string> <string name="install_failed" msgid="5777824004474125469">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເທື່ອ."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ແພັກເກດຖືກບລັອກບໍ່ໃຫ້ໄດ້ຮັບການຕິດຕັ້ງ."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເນື່ອງຈາກແພັກເກດຂັດແຍ່ງກັບແພັກເກດທີ່ມີຢູ່ກ່ອນແລ້ວ."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ຜູ້ໃຊ້ນີ້ບໍ່ສາມາດຕິດຕັ້ງແອັບທີ່ບໍ່ຮູ້ຈັກໄດ້"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ຜູ້ໃຊ້ນີ້ບໍ່ໄດ້ຮັບອະນຸຍາດໃຫ້ຕິດຕັ້ງແອັບໄດ້"</string> <string name="ok" msgid="7871959885003339302">"ຕົກລົງ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"ຢືນຢັນການອັບເດດ"</string> <string name="manage_applications" msgid="5400164782453975580">"ຈັດການແອັບ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ພື້ນທີ່ຫວ່າງບໍ່ພຽງພໍ"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"ບໍ່ສາມາດຕິດຕັ້ງ <xliff:g id="APP_NAME">%1$s</xliff:g> ໄດ້. ກະລຸນາລຶບຂໍ້ມູນທີ່ບໍ່ຈຳເປັນອອກເພື່ອໃຫ້ມີບ່ອນຈັດເກັບຂໍ້ມູນຫວ່າງເພີ່ມຂຶ້ນ ແລ້ວລອງໃໝ່ອີກຄັ້ງ."</string> diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml index 55a9f3ca0c9a..17dd542bd787 100644 --- a/packages/PackageInstaller/res/values-lv/strings.xml +++ b/packages/PackageInstaller/res/values-lv/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Lietotne ir instalēta."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vai vēlaties instalēt šo lietotni?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vai vēlaties atjaunināt šo lietotni?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vai atjaunināt šo lietotni, izmantojot “<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>”?\n\nŠī lietotne parasti saņem atjauninājumus no “<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>”. Veicot atjaunināšanu no cita avota, iespējams, turpmāk tālrunī saņemsiet atjauninājumus no jebkāda avota. Lietotnes funkcionalitāte var mainīties."</string> <string name="install_failed" msgid="5777824004474125469">"Lietotne nav instalēta."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Pakotnes instalēšana tika bloķēta."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Lietotne netika instalēta, jo pastāv pakotnes konflikts ar esošu pakotni."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Šis lietotājs nevar instalēt nezināmas lietotnes"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Šim lietotājam nav atļauts instalēt lietotnes"</string> <string name="ok" msgid="7871959885003339302">"Labi"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Tik un tā atjaunināt"</string> <string name="manage_applications" msgid="5400164782453975580">"Pārv. lietotnes"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nav brīvas vietas"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Lietotni <xliff:g id="APP_NAME">%1$s</xliff:g> nevarēja instalēt. Atbrīvojiet vietu un mēģiniet vēlreiz."</string> diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml index 4024d8a62810..b8bb6b9c9078 100644 --- a/packages/PackageInstaller/res/values-mk/strings.xml +++ b/packages/PackageInstaller/res/values-mk/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Апликацијата е инсталирана."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Дали сакате да ја инсталирате апликацијава?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Дали сакате да ја ажурирате апликацијава?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Ажурирајте ја апликацијава од <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nАпликацијава вообичаено добива ажурирања од<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Со ажурирање од различен извор, може да добивате идни ажурирања од кој било извор на вашиот телефон. Функционалноста на апликацијата може да се промени."</string> <string name="install_failed" msgid="5777824004474125469">"Апликацијата не е инсталирана."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирањето на пакетот е блокирано."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Апликација што не е инсталирана како пакет е во конфликт со постоечки пакет."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Корисников не може да инсталира непознати апликации"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"На корисников не му е дозволено да инсталира апликации"</string> <string name="ok" msgid="7871959885003339302">"Во ред"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Сепак ажурирај"</string> <string name="manage_applications" msgid="5400164782453975580">"Управување со апликациите"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Нема простор"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> не може да се инсталира. Ослободете простор и обидете се повторно."</string> diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml index 42790b2d5f26..053584363af7 100644 --- a/packages/PackageInstaller/res/values-ml/strings.xml +++ b/packages/PackageInstaller/res/values-ml/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തു."</string> <string name="install_confirm_question" msgid="7663733664476363311">"ഈ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> എന്നതിൽ നിന്ന് ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?\n\nഈ ആപ്പിന് സാധാരണയായി <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> എന്നതിൽ നിന്ന് അപ്ഡേറ്റുകൾ ലഭിക്കാറുണ്ട്. മറ്റൊരു ഉറവിടത്തിൽ നിന്ന് അപ്ഡേറ്റ് ചെയ്യുന്നത് വഴി, നിങ്ങളുടെ ഫോണിലെ ഏത് ഉറവിടത്തിൽ നിന്നും ഭാവിയിൽ അപ്ഡേറ്റുകൾ ലഭിക്കാൻ ഇടയുണ്ട്. ആപ്പ് ഫംഗ്ഷണാലിറ്റിയിൽ വ്യത്യാസം വന്നേക്കാം."</string> <string name="install_failed" msgid="5777824004474125469">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"പാക്കേജ് ഇൻസ്റ്റാൾ ചെയ്യുന്നത് ബ്ലോക്ക് ചെയ്തു."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"പാക്കേജിന് നിലവിലുള്ള പാക്കേജുമായി പൊരുത്തക്കേടുള്ളതിനാൽ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തില്ല."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ഈ ഉപയോക്താവിന്, അജ്ഞാത ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യാനാവില്ല"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യാൻ ഈ ഉപയോക്താവിന് അനുവാദമില്ല"</string> <string name="ok" msgid="7871959885003339302">"ശരി"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"എന്തായാലും അപ്ഡേറ്റ് ചെയ്യുക"</string> <string name="manage_applications" msgid="5400164782453975580">"ആപ്പുകൾ മാനേജ് ചെയ്യുക"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ഇടമില്ല"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല. കുറച്ച് ഇടമുണ്ടാക്കി, വീണ്ടും ശ്രമിക്കുക."</string> diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml index 01e7aec37f5e..84a3909bb706 100644 --- a/packages/PackageInstaller/res/values-mn/strings.xml +++ b/packages/PackageInstaller/res/values-mn/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Аппыг суулгасан."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Та энэ аппыг суулгахыг хүсэж байна уу?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Та энэ аппыг шинэчлэхийг хүсэж байна уу?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Аппыг <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-с шинэчлэх үү?\n\nЭнэ апп ихэвчлэн <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-с шинэчлэлт хүлээн авдаг. Өөр эх сурвалжаас шинэчилснээр та ирээдүйн шинэчлэлтийг утсан дээрх аливаа эх сурвалжаас хүлээн авч магадгүй. Аппын ажиллагаа өөрчлөгдөж магадгүй."</string> <string name="install_failed" msgid="5777824004474125469">"Аппыг суулгаагүй."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Багц суулгахыг блоклосон байна."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Багц одоо байгаа багцтай тохирохгүй байгаа тул аппыг суулгаж чадсангүй."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Энэ хэрэглэгч тодорхойгүй апп суулгах боломжгүй"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Энэ хэрэглэгч нь апп суулгах зөвшөөрөлгүй байна"</string> <string name="ok" msgid="7871959885003339302">"ОК"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Ямартай ч шинэчлэх"</string> <string name="manage_applications" msgid="5400164782453975580">"Аппуудыг удирдах"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Орон зай дутагдаж байна"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г суулгаж чадсангүй. Хэсэг зай чөлөөлөөд дахин оролдоно уу."</string> diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml index 5ae257af3ea0..367dede86ebf 100644 --- a/packages/PackageInstaller/res/values-mr/strings.xml +++ b/packages/PackageInstaller/res/values-mr/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"अॅप इंस्टॉल झाले."</string> <string name="install_confirm_question" msgid="7663733664476363311">"तुम्हाला हे ॲप इंस्टॉल करायचे आहे का?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"तुम्हाला हे ॲप अपडेट करायचे आहे का?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> वरून हे अॅप अपडेट करायचे आहे का?\n\nया अॅपला सामान्यतः <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> कडून अपडेट मिळतात. वेगवेगळ्या स्रोताकडून अपडेट करून, तुम्हाला तुमच्या फोनवरील कोणत्याही स्रोताकडून भविष्यातील अपडेट मिळू शकतात. अॅपची कार्यक्षमता बदलू शकते."</string> <string name="install_failed" msgid="5777824004474125469">"अॅप इंस्टॉल झाले नाही."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"पॅकेज इंस्टॉल होण्यापासून ब्लॉक केले होते."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"पॅकेजचा विद्यमान पॅकेजशी विरोध असल्याने अॅप इंस्टॉल झाले नाही."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"या वापरकर्त्याद्वारे अज्ञात अॅप्स इंस्टॉल केली जाऊ शकत नाहीत"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"या वापरकर्त्याला अॅप्स इंस्टॉल करण्याची अनुमती नाही"</string> <string name="ok" msgid="7871959885003339302">"ओके"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"तरीही अपडेट करा"</string> <string name="manage_applications" msgid="5400164782453975580">"अॅप्स व्यवस्थापन"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"जागा संपली"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> इंस्टॉल केले जाऊ शकत नाही. काही जागा मोकळी करा आणि पुन्हा प्रयत्न करा."</string> diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml index a26d2743c4f7..6ab6622e75e2 100644 --- a/packages/PackageInstaller/res/values-ms/strings.xml +++ b/packages/PackageInstaller/res/values-ms/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikasi dipasang."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Adakah anda ingin memasang aplikasi ini?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Adakah anda mahu mengemas kini apl ini?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Kemas kinikan apl ini daripada <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nApl ini biasanya menerima kemaskinian daripada <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan membuat kemaskinian daripada sumber yang berbeza, anda mungkin menerima kemaskinian masa hadapan daripada sebarang sumber pada telefon anda. Fungsi apl mungkin berubah."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak dipasang."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Pakej ini telah disekat daripada dipasang."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Apl tidak dipasang kerana pakej bercanggah dengan pakej yang sedia ada."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Apl yang tidak diketahui tidak boleh dipasang oleh pengguna ini"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Pengguna ini tidak dibenarkan memasang apl"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Kemas kinikan juga"</string> <string name="manage_applications" msgid="5400164782453975580">"Urus apl"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Kehabisan ruang"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak dapat dipasang. Kosongkan sebahagian ruang dan cuba lagi."</string> diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml index db21cf71f473..4844d58a590b 100644 --- a/packages/PackageInstaller/res/values-my/strings.xml +++ b/packages/PackageInstaller/res/values-my/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"အက်ပ်ထည့်သွင်းပြီးပါပြီ။"</string> <string name="install_confirm_question" msgid="7663733664476363311">"ဤအက်ပ်ကို ထည့်သွင်းလိုသလား။"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ဤအက်ပ်ကို အပ်ဒိတ်လုပ်လိုသလား။"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ဤအက်ပ်ကို <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> မှ အပ်ဒိတ်လုပ်မလား။\n\nဤအက်ပ်သည် ပုံမှန်အားဖြင့် <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> မှ အပ်ဒိတ်များ ရရှိသည်။ မတူညီသောရင်းမြစ်မှ အပ်ဒိတ်လုပ်ခြင်းဖြင့် ဖုန်းပေါ်တွင် နောင်လာမည့်အပ်ဒိတ်များကို မည်သည့်ရင်းမြစ်မဆိုမှ လက်ခံရယူနိုင်သည်။ အက်ပ်လုပ်ဆောင်ချက် ပြောင်းလဲနိုင်သည်။"</string> <string name="install_failed" msgid="5777824004474125469">"အက်ပ်မထည့်သွင်းရသေးပါ"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ပက်ကေ့ဂျ်ထည့်သွင်းခြင်းကို ပိတ်ထားသည်။"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ပက်ကေ့ဂျ်အဖြစ် ထည့်သွင်းမထားသော အက်ပ်သည် လက်ရှိပက်ကေ့ဂျ်နှင့် တိုက်နေသည်။"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"အရင်းအမြစ်မသိသော အက်ပ်များကို ဤအသုံးပြုသူက ထည့်သွင်းခွင့်မရှိပါ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ဤအသုံးပြုသူသည် အက်ပ်များကို ထည့်သွင်းခွင့်မရှိပါ"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"ဘာဖြစ်ဖြစ် အပ်ဒိတ်လုပ်ရန်"</string> <string name="manage_applications" msgid="5400164782453975580">"အက်ပ်စီမံခြင်း"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"နေရာလွတ်မရှိပါ"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ထည့်သွင်း၍ မရနိုင်ပါ။ နေရာလွတ်ပြုလုပ်ပြီး ထပ်စမ်းကြည့်ပါ။"</string> diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml index 94b7f50d1056..7532d7b3e96f 100644 --- a/packages/PackageInstaller/res/values-nb/strings.xml +++ b/packages/PackageInstaller/res/values-nb/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Appen er installert."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne appen?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du oppdatere denne appen?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vil du oppdatere denne appen fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne appen mottar vanligvis oppdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du oppdaterer fra en annen kilde, kan du få fremtidige oppdateringer fra en hvilken som helst kilde på telefonen. Appfunksjonaliteten kan endres."</string> <string name="install_failed" msgid="5777824004474125469">"Appen ble ikke installert."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Pakken er blokkert fra å bli installert."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Appen ble ikke installert fordi pakken er i konflikt med en eksisterende pakke."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ukjente apper kan ikke installeres av denne brukeren"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Brukeren har ikke tillatelse til å installere apper"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Oppdater likevel"</string> <string name="manage_applications" msgid="5400164782453975580">"Administrer apper"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Tom for plass"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> kunne ikke installeres. Frigjør plass og prøv på nytt."</string> diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml index d531d5ce3a7a..14f387f819ea 100644 --- a/packages/PackageInstaller/res/values-ne/strings.xml +++ b/packages/PackageInstaller/res/values-ne/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"एप इन्स्टल गरियो।"</string> <string name="install_confirm_question" msgid="7663733664476363311">"तपाईं यो एप इन्स्टल गर्न चाहनुहुन्छ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"तपाईं यो एप अपडेट गर्न चाहनुहुन्छ?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"यो एप <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> बाट अपडेट गर्ने हो?\n\nयो एपले सामान्यतया <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> बाट अपडेट प्राप्त गर्छ। तपाईंले कुनै फरक स्रोतबाट अपडेट गर्नुभयो भने तपाईं भविष्यमा आफ्नो फोनमा भएको जुनसुकै स्रोतबाट अपडेटहरू प्राप्त गर्न सक्नुहुन्छ। यसो गर्दा एपको विशेषता परिवर्तन हुन सक्छ।"</string> <string name="install_failed" msgid="5777824004474125469">"एप स्थापना गरिएन।"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"यी प्रयोगकर्ता अज्ञात एपहरू इन्स्टल गर्न सक्नुहुन्न"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"यो प्रयोगकर्तालाई एपहरू इन्स्टल गर्ने अनुमति छैन"</string> <string name="ok" msgid="7871959885003339302">"ठिक छ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"जे भए पनि अपडेट गर्नुहोस्"</string> <string name="manage_applications" msgid="5400164782453975580">"एपको प्रबन्ध गर्नु…"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"खाली ठाउँ छैन"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन। केही ठाउँ खाली गरेर फेरि प्रयास गर्नुहोस्।"</string> diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml index ad4df64fe6f3..fab6d5163627 100644 --- a/packages/PackageInstaller/res/values-nl/strings.xml +++ b/packages/PackageInstaller/res/values-nl/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App geïnstalleerd."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Wil je deze app installeren?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Wil je deze app updaten?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Deze app updaten via <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDeze app krijgt gewoonlijk updates via <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Als je updatet via een andere bron, kun je toekomstige updates via elke bron op je telefoon krijgen. De app-functionaliteit kan veranderen."</string> <string name="install_failed" msgid="5777824004474125469">"App niet geïnstalleerd."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"De installatie van het pakket is geblokkeerd."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"App die niet is geïnstalleerd als pakket conflicteert met een bestaand pakket."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Onbekende apps kunnen niet worden geïnstalleerd door deze gebruiker"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Deze gebruiker mag geen apps installeren"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Toch updaten"</string> <string name="manage_applications" msgid="5400164782453975580">"Apps beheren"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Geen ruimte beschikbaar"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan niet worden geïnstalleerd. Maak ruimte vrij en probeer het opnieuw."</string> diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml index db908fd14f0c..ee6fa60a0643 100644 --- a/packages/PackageInstaller/res/values-or/strings.xml +++ b/packages/PackageInstaller/res/values-or/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ଆପ ଇନଷ୍ଟଲ ହୋଇଗଲା।"</string> <string name="install_confirm_question" msgid="7663733664476363311">"ଆପଣ ଏହି ଆପକୁ ଇନଷ୍ଟଲ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ଆପଣ ଏହି ଆପକୁ ଅପଡେଟ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ରୁ ଏହି ଆପକୁ ଅପଡେଟ କରିବେ?\n\nଏହି ଆପ ସାଧାରଣତଃ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ରୁ ଅପଡେଟ ପାଇଥାଏ। ଏକ ଭିନ୍ନ ସୋର୍ସରୁ ଅପଡେଟ କରି ଆପଣ ଆପଣଙ୍କ ଫୋନରେ ଯେ କୌଣସି ସୋର୍ସରୁ ଭବିଷ୍ୟତର ଅପଡେଟଗୁଡ଼ିକ ପାଇପାରନ୍ତି। ଆପ କାର୍ଯ୍ୟକ୍ଷମତା ପରିବର୍ତ୍ତନ ହୋଇପାରେ।"</string> <string name="install_failed" msgid="5777824004474125469">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇନାହିଁ।"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ଏହି ପ୍ୟାକେଜ୍କୁ ଇନଷ୍ଟଲ୍ କରାଯିବାରୁ ଅବରୋଧ କରାଯାଇଥିଲା।"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ପୂର୍ବରୁ ଥିବା ପ୍ୟାକେଜ୍ ସହ ଏହି ପ୍ୟାକେଜ୍ର ସମସ୍ୟା ଉପୁଯିବାରୁ ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇପାରିଲା ନାହିଁ।"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ଏହି ୟୁଜରଙ୍କ ଦ୍ୱାରା ଅଜଣା ଆପ୍ ଇନଷ୍ଟଲ୍ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ଏହି ୟୁଜର୍ ଆପ୍ ଇନଷ୍ଟଲ୍ କରିପାରିବେ ନାହିଁ"</string> <string name="ok" msgid="7871959885003339302">"ଠିକ୍ ଅଛି"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"ଯେ କୌଣସି ମତେ ଅପଡେଟ କରନ୍ତୁ"</string> <string name="manage_applications" msgid="5400164782453975580">"ଆପ୍ଗୁଡ଼ିକର ପରିଚାଳନା କରନ୍ତୁ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ଆଉ ସ୍ଥାନ ନାହିଁ"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ କରାଯାଇପାରିଲା ନାହିଁ। କିଛି ସ୍ଥାନ ଖାଲିକରି ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string> diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml index 64dd9c7c1503..1ef49215b8e2 100644 --- a/packages/PackageInstaller/res/values-pa/strings.xml +++ b/packages/PackageInstaller/res/values-pa/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ਐਪ ਸਥਾਪਤ ਕੀਤੀ ਗਈ।"</string> <string name="install_confirm_question" msgid="7663733664476363311">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ਕੀ ਇਸ ਐਪ ਨੂੰ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?\n\nਇਸ ਐਪ ਨੂੰ ਆਮ ਤੌਰ \'ਤੇ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਹੁੰਦੀਆਂ ਹਨ। ਕਿਸੇ ਵੱਖਰੇ ਸਰੋਤ ਤੋਂ ਅੱਪਡੇਟ ਕਰ ਕੇ, ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਕਿਸੇ ਵੀ ਸਰੋਤ ਤੋਂ ਭਵਿੱਖੀ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ। ਐਪ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਬਦਲ ਸਕਦੀ ਹੈ।"</string> <string name="install_failed" msgid="5777824004474125469">"ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ਪੈਕੇਜ ਨੂੰ ਸਥਾਪਤ ਹੋਣ ਤੋਂ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਸੀ।"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ਪੈਕੇਜ ਦੇ ਇੱਕ ਮੌਜੂਦਾ ਪੈਕੇਜ ਨਾਲ ਵਿਵਾਦ ਹੋਣ ਕਰਕੇ ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ਇਹ ਵਰਤੋਂਕਾਰ ਅਗਿਆਤ ਐਪਾਂ ਨੂੰ ਸਥਾਪਤ ਨਹੀਂ ਕਰ ਸਕਦਾ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਐਪਾਂ ਸਥਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string> <string name="ok" msgid="7871959885003339302">"ਠੀਕ ਹੈ"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"ਫਿਰ ਵੀ ਅੱਪਡੇਟ ਕਰੋ"</string> <string name="manage_applications" msgid="5400164782453975580">"ਐਪਾਂ ਪ੍ਰਬੰਧਿਤ ਕਰੋ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ਜਗ੍ਹਾ ਖਾਲੀ ਨਹੀਂ"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਕੁਝ ਜਗ੍ਹਾ ਖਾਲੀ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml index c05c81a6f7cc..e44a391c2ee6 100644 --- a/packages/PackageInstaller/res/values-pl/strings.xml +++ b/packages/PackageInstaller/res/values-pl/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikacja została zainstalowana."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Zainstalować tę aplikację?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Zaktualizować tę aplikację?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Zastosować do aplikacji aktualizację pochodzącą z tego źródła (<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>)?\n\nAktualizacje dla tej aplikacji zwykle dostarcza <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Jeśli zastosujesz aplikację pochodzącą z innego źródła, możesz w przyszłości otrzymywać na telefonie aktualizacje z dowolnych źródeł. Funkcje aplikacji mogą się zmienić."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikacja nie została zainstalowana."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Instalacja pakietu została zablokowana."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacja nie została zainstalowana, bo powoduje konflikt z istniejącym pakietem."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ten użytkownik nie może instalować nieznanych aplikacji"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ten użytkownik nie może instalować aplikacji"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Zaktualizuj mimo to"</string> <string name="manage_applications" msgid="5400164782453975580">"Zarządzaj aplikacjami"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Brak miejsca"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Nie można zainstalować aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>. Zwolnij trochę miejsca i spróbuj ponownie."</string> diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml index f2eab25522eb..990895caacd4 100644 --- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml +++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App instalado."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAs atualizações dele normalmente são feitas com <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ao atualizar usando uma origem diferente, as próximas atualizações poderão ser feitas com qualquer origem no seu smartphone. A funcionalidade do app pode mudar."</string> <string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Apps desconhecidos não podem ser instalados por este usuário"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuário não tem permissão para instalar apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Atualizar mesmo assim"</string> <string name="manage_applications" msgid="5400164782453975580">"Gerenciar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sem espaço"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Não foi possível instalar <xliff:g id="APP_NAME">%1$s</xliff:g>. Libere um pouco de espaço e tente novamente."</string> diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml index c44088056405..aff06e962e45 100644 --- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml +++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App instalada."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Instalar esta app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Pretende atualizar esta app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Atualizar esta app a partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNormalmente, esta app recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se atualizar a partir de uma origem diferente, poderá receber futuras atualizações de qualquer origem no seu telemóvel. A funcionalidade da app pode sofrer alterações."</string> <string name="install_failed" msgid="5777824004474125469">"Aplicação não instalada."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Foi bloqueada a instalação do pacote."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"A app não foi instalada porque o pacote entra em conflito com um pacote existente."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este utilizador não pode instalar aplicações desconhecidas."</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este utilizador não tem autorização para instalar aplicações."</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Atualizar mesmo assim"</string> <string name="manage_applications" msgid="5400164782453975580">"Gerir app"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sem espaço"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Não foi possível instalar a app <xliff:g id="APP_NAME">%1$s</xliff:g>. Liberte algum espaço e tente novamente."</string> diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml index f2eab25522eb..990895caacd4 100644 --- a/packages/PackageInstaller/res/values-pt/strings.xml +++ b/packages/PackageInstaller/res/values-pt/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"App instalado."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAs atualizações dele normalmente são feitas com <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ao atualizar usando uma origem diferente, as próximas atualizações poderão ser feitas com qualquer origem no seu smartphone. A funcionalidade do app pode mudar."</string> <string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Apps desconhecidos não podem ser instalados por este usuário"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuário não tem permissão para instalar apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Atualizar mesmo assim"</string> <string name="manage_applications" msgid="5400164782453975580">"Gerenciar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sem espaço"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Não foi possível instalar <xliff:g id="APP_NAME">%1$s</xliff:g>. Libere um pouco de espaço e tente novamente."</string> diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml index f12e3648aaba..de4dd5548f8f 100644 --- a/packages/PackageInstaller/res/values-ro/strings.xml +++ b/packages/PackageInstaller/res/values-ro/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplicație instalată."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vrei să instalezi această aplicație?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vrei să actualizezi această aplicație?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Actualizezi aplicația de la <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDe obicei, aplicația primește actualizări de la <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dacă actualizezi din altă sursă, este posibil să primești actualizări viitoare din orice sursă pe telefon. Funcționalitatea aplicației se poate modifica."</string> <string name="install_failed" msgid="5777824004474125469">"Aplicația nu a fost instalată."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Instalarea pachetului a fost blocată."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplicația nu a fost instalată deoarece pachetul intră în conflict cu un pachet existent."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aplicațiile necunoscute nu pot fi instalate de acest utilizator"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Acest utilizator nu are permisiunea să instaleze aplicații"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Actualizează oricum"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestionează"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Spațiu de stocare insuficient"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Aplicația <xliff:g id="APP_NAME">%1$s</xliff:g> nu a putut fi instalată. Eliberează spațiu și încearcă din nou."</string> diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml index e7e9e33b2de4..2e28c300cb5f 100644 --- a/packages/PackageInstaller/res/values-ru/strings.xml +++ b/packages/PackageInstaller/res/values-ru/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Приложение установлено."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Установить приложение?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Обновить приложение?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Обновить приложение с помощью <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nОбычно обновления для этого приложения поступают из <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Если обновить приложение с помощью другого источника, в будущем для этого могут использоваться любые источники на телефоне. Функции приложения могут измениться."</string> <string name="install_failed" msgid="5777824004474125469">"Приложение не установлено."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Установка пакета заблокирована."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Приложение не установлено, так как оно конфликтует с другим пакетом."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Этот пользователь не может устанавливать неизвестные приложения."</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Этому пользователю не разрешено устанавливать приложения."</string> <string name="ok" msgid="7871959885003339302">"ОК"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Все равно обновить"</string> <string name="manage_applications" msgid="5400164782453975580">"Управление приложениями"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Недостаточно места"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Не удалось установить приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\". Освободите место на устройстве и повторите попытку."</string> diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml index 0f5dbb6d68a9..c300b68c17a1 100644 --- a/packages/PackageInstaller/res/values-si/strings.xml +++ b/packages/PackageInstaller/res/values-si/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"යෙදුම ස්ථාපනය කර ඇත."</string> <string name="install_confirm_question" msgid="7663733664476363311">"මෙම යෙදුම ස්ථාපනය කිරීමට ඔබට අවශ්යද?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"ඔබට මෙම යෙදුම යාවත්කාලීන කිරීමට අවශ්යද?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> වෙතින් මෙම යෙදුම යාවත්කාලීන කරන්න ද?\n\nමෙම යෙදුමට සාමාන්යයෙන් <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> සිට යාවත්කාලීන ලැබේ. වෙනස් මූලාශ්රයකින් යාවත්කාලීන කිරීමෙන්, ඔබට ඔබේ දුරකථනයෙහි ඕනෑම මූලාශ්රයකින් අනාගත යාවත්කාලීන ලැබීමට ඉඩ ඇත. යෙදුම් ක්රියාකාරිත්වය වෙනස් වීමට ඉඩ ඇත."</string> <string name="install_failed" msgid="5777824004474125469">"යෙදුම ස්ථාපනය කර නැත."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"මෙම පැකේජය ස්ථාපනය කිරීම අවහිර කරන ලදි."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"පැකේජය දැනට පවතින පැකේජයක් සමග ගැටෙන නිසා යෙදුම ස්ථාපනය නොකරන ලදී."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"මෙම පරිශීලකයා මඟින් නොදන්නා යෙදුම් ස්ථාපනය කළ නොහැක"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"මෙම පරිශීලකයාට යෙදුම් ස්ථාපනය කිරීමට අවසර නැත"</string> <string name="ok" msgid="7871959885003339302">"හරි"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"කෙසේ වෙතත් යාවත්කාලීන කරන්න"</string> <string name="manage_applications" msgid="5400164782453975580">"යෙදුම් කළමනාකරණය කරන්න"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ඉඩ නොමැත"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ස්ථාපිත කිරීමට නොහැකි විය. ඉඩ පොඩ්ඩක් නිදහස් කොට නැවත උත්සාහ කරන්න."</string> diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml index 8363fb6117cc..0afce1be3e1c 100644 --- a/packages/PackageInstaller/res/values-sk/strings.xml +++ b/packages/PackageInstaller/res/values-sk/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikácia bola nainštalovaná."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Chcete túto aplikáciu nainštalovať?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete túto aplikáciu aktualizovať?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Chcete aktualizovať túto aplikáciu zo zdroja <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTáto aplikácia obvykle dostáva aktualizácie zo zdroja <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ak aktualizujete z iného zdroja, môžete v budúcnosti dostávať aktualizácie z ľubovoľného zdroja v telefóne. Funkcie aplikácie sa môžu zmeniť."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikácia nebola nainštalovaná."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Inštalácia balíka bola zablokovaná."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikácia sa nenainštalovala, pretože balík je v konflikte s existujúcim balíkom."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Tento používateľ nemôže inštalovať neznáme aplikácie"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Tento používateľ nemá povolené inštalovať aplikácie"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Napriek tomu aktualizovať"</string> <string name="manage_applications" msgid="5400164782453975580">"Spravovať aplikácie"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nedostatok miesta"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> sa nepodarilo nainštalovať. Uvoľnite miesto v pamäti a skúste to znova."</string> diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml index 5c2897965f14..00c3d152f75f 100644 --- a/packages/PackageInstaller/res/values-sl/strings.xml +++ b/packages/PackageInstaller/res/values-sl/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikacija je nameščena."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Ali želite namestiti to aplikacijo?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Ali želite posodobiti to aplikacijo?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Želite to aplikacijo posodobiti iz vira <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTa aplikacija običajno prejema posodobitve iz vira <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Če jo posodobite iz drugega vira, boste prihodnje posodobitve morda prejemali iz katerega koli vira v telefonu. Funkcija aplikacije se lahko spremeni."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikacija ni nameščena."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Namestitev paketa je bila blokirana."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija ni bila nameščena, ker je paket v navzkrižju z obstoječim paketom."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ta uporabnik nima dovoljenja za nameščanje neznanih aplikacij"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ta uporabnik nima dovoljenja za nameščanje aplikacij"</string> <string name="ok" msgid="7871959885003339302">"V redu"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Vseeno posodobi"</string> <string name="manage_applications" msgid="5400164782453975580">"Upravlj. aplik."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Zmanjkalo je prostora"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> ni bilo mogoče namestiti. Sprostite prostor in poskusite znova."</string> diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml index 709b7fd5bc3e..9904bc04be50 100644 --- a/packages/PackageInstaller/res/values-sq/strings.xml +++ b/packages/PackageInstaller/res/values-sq/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Aplikacioni u instalua."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Dëshiron ta instalosh këtë aplikacion?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Dëshiron ta përditësosh këtë aplikacion?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Të përditësohet ky aplikacion nga <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKy aplikacion zakonisht merr përditësime nga <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Duke përditësuar nga një burim tjetër, mund të marrësh përditësime të ardhshme nga çdo burim në telefonin tënd. Funksionaliteti i aplikacionit mund të ndryshojë."</string> <string name="install_failed" msgid="5777824004474125469">"Aplikacioni nuk u instalua."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Instalimi paketës u bllokua."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacioni nuk u instalua pasi paketa është në konflikt me një paketë ekzistuese."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aplikacionet e panjohura nuk mund të instalohen nga ky përdorues"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ky përdorues nuk lejohet të instalojë aplikacione"</string> <string name="ok" msgid="7871959885003339302">"Në rregull"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Përditësoje gjithsesi"</string> <string name="manage_applications" msgid="5400164782453975580">"Menaxho aplikacionet"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nuk ka hapësirë"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mund të instalohej. Liro pak hapësirë dhe provo përsëri."</string> diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml index 3a62db3af95a..5a0f52d02182 100644 --- a/packages/PackageInstaller/res/values-sr/strings.xml +++ b/packages/PackageInstaller/res/values-sr/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Апликација је инсталирана."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Желите да инсталирате ову апликацију?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Желите да ажурирате ову апликацију?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Желите да ажурирате ову апликацију из извора <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nОва апликација се обично ажурира из извора <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако ажурирате из другог извора, можете да примате будућа ажурирања из било ког извора на телефону. Функције апликације могу да се промене."</string> <string name="install_failed" msgid="5777824004474125469">"Апликација није инсталирана."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирање пакета је блокирано."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Апликација није инсталирана јер је пакет неусаглашен са постојећим пакетом."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Овај корисник не може да инсталира непознате апликације"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Овом кориснику није дозвољено да инсталира апликације"</string> <string name="ok" msgid="7871959885003339302">"Потврди"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Ипак ажурирај"</string> <string name="manage_applications" msgid="5400164782453975580">"Управљајте апл."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Нема више простора"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Нисмо успели да инсталирамо апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>. Ослободите простор и пробајте поново."</string> diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml index d8ed4b1ce62a..ec6af2e59897 100644 --- a/packages/PackageInstaller/res/values-sv/strings.xml +++ b/packages/PackageInstaller/res/values-sv/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Appen har installerats."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vill du installera den här appen?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vill du uppdatera den här appen?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vill du uppdatera den här appen från <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAppen tar vanligtvis emot uppdateringar från <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Genom att uppdatera från en annan källa kan du komma att ta emot framtida uppdateringar från olika källor på telefonen. Appfunktioner kan förändras."</string> <string name="install_failed" msgid="5777824004474125469">"Appen har inte installerats."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paketet har blockerats för installation."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Appen har inte installerats på grund av en konflikt mellan detta paket och ett befintligt paket."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Denna användare får inte installera okända appar"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Användaren har inte behörighet att installera appar"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Uppdatera ändå"</string> <string name="manage_applications" msgid="5400164782453975580">"Hantera appar"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Slut på utrymme"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Det gick inte att avinstallera <xliff:g id="APP_NAME">%1$s</xliff:g>. Frigör minne och försök igen."</string> diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml index 4919cb55ab01..d396472384c0 100644 --- a/packages/PackageInstaller/res/values-sw/strings.xml +++ b/packages/PackageInstaller/res/values-sw/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Imesakinisha programu."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Ungependa kusakinisha programu hii?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Ungependa kusasisha programu hii?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Ungependa kusasisha hii programu kutoka kwa<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nProgramu hii kwa kawaida hupokea masasisho kutoka kwa <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kwa kusasisha kutoka chanzo tofauti, huenda ukapokea masasisho ya siku zijazo kutoka chanzo chochote kwenye simu yako. Utendaji wa programu unaweza kubadilika."</string> <string name="install_failed" msgid="5777824004474125469">"Imeshindwa kusakinisha programu."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Kifurushi kimezuiwa kisisakinishwe."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Programu haikusakinishwa kwa sababu kifurushi kinakinzana na kifurushi kingine kilichopo."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Mtumiaji huyu hana idhini ya kusakinisha programu ambazo hazijulikani"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Mtumiaji huyu haruhusiwi kusakinisha programu"</string> <string name="ok" msgid="7871959885003339302">"Sawa"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Sasisha tu"</string> <string name="manage_applications" msgid="5400164782453975580">"Dhibiti programu"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nafasi imejaa"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Imeshindwa kusakinisha <xliff:g id="APP_NAME">%1$s</xliff:g>. Futa baadhi ya maudhui ili upate nafasi kisha ujaribu tena."</string> diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml index d867ee89c570..c60910c05714 100644 --- a/packages/PackageInstaller/res/values-ta/strings.xml +++ b/packages/PackageInstaller/res/values-ta/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ஆப்ஸ் நிறுவப்பட்டது."</string> <string name="install_confirm_question" msgid="7663733664476363311">"இந்த ஆப்ஸை நிறுவ வேண்டுமா?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> இலிருந்து இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?\n\nபொதுவாக இந்த ஆப்ஸ்<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> இலிருந்து புதுப்பிப்புகளைப் பெறும். வேறொன்றின் மூலம் புதுப்பித்தால் எதிர்காலத்தில் மொபைலில் வேறு இடத்திலிருந்து புதுப்பிப்புகளை நீங்கள் பெறக்கூடும். ஆப்ஸ் செயல்பாடுகள் மாறுபடக்கூடும்."</string> <string name="install_failed" msgid="5777824004474125469">"ஆப்ஸ் நிறுவப்படவில்லை."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"இந்தத் தொகுப்பு நிறுவப்படுவதிலிருந்து தடுக்கப்பட்டது."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"இந்தத் தொகுப்பு ஏற்கனவே உள்ள தொகுப்புடன் முரண்படுவதால் ஆப்ஸ் நிறுவப்படவில்லை."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"அறியப்படாத ஆப்ஸை இந்தப் பயனரால் நிறுவ இயலாது"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ஆப்ஸை நிறுவ இந்தப் பயனருக்கு அனுமதியில்லை"</string> <string name="ok" msgid="7871959885003339302">"சரி"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"பரவாயில்லை, புதுப்பிக்கவும்"</string> <string name="manage_applications" msgid="5400164782453975580">"ஆப்ஸை நிர்வகி"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"போதுமான சேமிப்பிடம் இல்லை"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸை நிறுவ இயலவில்லை. சிறிது சேமிப்பிடத்தைக் காலிசெய்து மீண்டும் முயலவும்."</string> diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml index 7e1c9daef4c4..2dd66bc375a9 100644 --- a/packages/PackageInstaller/res/values-te/strings.xml +++ b/packages/PackageInstaller/res/values-te/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"యాప్ ఇన్స్టాల్ చేయబడింది."</string> <string name="install_confirm_question" msgid="7663733664476363311">"మీరు ఈ యాప్ను ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"మీరు ఈ యాప్ను అప్డేట్ చేయాలనుకుంటున్నారా?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> నుండి ఈ యాప్ను అప్డేట్ చేయాలా?\n\nఈ యాప్ సాధారణంగా <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> నుండి అప్డేట్లను అందుకుంటుంది. విభిన్న సోర్స్ నుండి అప్డేట్ చేయడం ద్వారా, మీరు మీ ఫోన్లోని ఏదైనా సోర్స్ నుండి భవిష్యత్తు అప్డేట్లను పొందవచ్చు. యాప్ ఫంక్షనాలిటీ మారవచ్చు."</string> <string name="install_failed" msgid="5777824004474125469">"యాప్ ఇన్స్టాల్ చేయబడలేదు."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"ప్యాకేజీ ఇన్స్టాల్ కాకుండా బ్లాక్ చేయబడింది."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ప్యాకేజీ, అలాగే ఇప్పటికే ఉన్న ప్యాకేజీ మధ్య వైరుధ్యం ఉన్నందున యాప్ ఇన్స్టాల్ చేయబడలేదు."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ఈ వినియోగదారు తెలియని యాప్లను ఇన్స్టాల్ చేయలేరు"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"యాప్లను ఇన్స్టాల్ చేయడానికి ఈ వినియోగదారుకు అనుమతి లేదు"</string> <string name="ok" msgid="7871959885003339302">"సరే"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"ఏదేమైనా అప్డేట్ చేయండి"</string> <string name="manage_applications" msgid="5400164782453975580">"యాప్లను నిర్వహించండి"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ఖాళీ లేదు"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g>ని ఇన్స్టాల్ చేయడం సాధ్యపడలేదు. కొంత స్థలాన్ని ఖాళీ చేసి మళ్లీ ప్రయత్నించండి."</string> diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml index 37caaa7388f5..0bf2f84cb025 100644 --- a/packages/PackageInstaller/res/values-th/strings.xml +++ b/packages/PackageInstaller/res/values-th/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ติดตั้งแอปแล้ว"</string> <string name="install_confirm_question" msgid="7663733664476363311">"คุณต้องการติดตั้งแอปนี้ไหม"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"คุณต้องการอัปเดตแอปนี้ไหม"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"อัปเดตแอปนี้จาก <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ไหม\n\nโดยปกติแล้ว แอปนี้จะได้รับการอัปเดตจาก <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> การอัปเดตจากแหล่งที่มาอื่นอาจทำให้โทรศัพท์ของคุณได้รับการอัปเดตจากแหล่งที่มานั้นในอนาคต ฟังก์ชันการทำงานของแอปอาจมีการเปลี่ยนแปลง"</string> <string name="install_failed" msgid="5777824004474125469">"ไม่ได้ติดตั้งแอป"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"มีการบล็อกแพ็กเกจไม่ให้ติดตั้ง"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ไม่ได้ติดตั้งแอปเพราะแพ็กเกจขัดแย้งกับแพ็กเกจที่มีอยู่"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ผู้ใช้รายนี้ไม่สามารถติดตั้งแอปที่ไม่รู้จัก"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ผู้ใช้รายนี้ไม่ได้รับอนุญาตให้ติดตั้งแอป"</string> <string name="ok" msgid="7871959885003339302">"ตกลง"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"อัปเดตเลย"</string> <string name="manage_applications" msgid="5400164782453975580">"จัดการแอป"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ไม่มีพื้นที่"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"ติดตั้ง <xliff:g id="APP_NAME">%1$s</xliff:g> ไม่ได้ เพิ่มพื้นที่ว่างแล้วลองอีกครั้ง"</string> diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml index 87c408ae3684..4d516b587008 100644 --- a/packages/PackageInstaller/res/values-tl/strings.xml +++ b/packages/PackageInstaller/res/values-tl/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Na-install na ang app."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Gusto mo bang i-install ang app na ito?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Gusto mo bang i-update ang app na ito?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"I-update itong app na mula sa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKaraniwang nakakatanggap ang app na ito ng mga update mula sa <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Sa pag-update mula sa ibang pinagmulan, puwede kang makatanggap ng mga update mula sa anumang pinagmulan sa iyong telepono sa hinaharap. Posibleng magbago ang functionality ng app."</string> <string name="install_failed" msgid="5777824004474125469">"Hindi na-install ang app."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Na-block ang pag-install sa package."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Hindi na-install ang app dahil nagkakaproblema ang package sa isang dati nang package."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Hindi maaaring mag-install ang user na ito ng mga hindi kilalang app"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Hindi pinapayagan ang user na ito na mag-install ng mga app"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"I-update pa rin"</string> <string name="manage_applications" msgid="5400164782453975580">"Pamahalaan ang app"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Wala nang espasyo"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Hindi ma-install ang <xliff:g id="APP_NAME">%1$s</xliff:g>. Magbakante ng ilang espasyo at subukan ulit."</string> diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml index a775b4c36fa7..050d3986da20 100644 --- a/packages/PackageInstaller/res/values-tr/strings.xml +++ b/packages/PackageInstaller/res/values-tr/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Uygulama yüklendi."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Bu uygulamayı yüklemek istiyor musunuz?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Bu uygulamayı güncellemek istiyor musunuz?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Bu uygulama <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> kaynağından güncellensin mi?\n\nBu uygulama genellikle <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> kaynağından güncelleme alır. Farklı bir kaynaktan güncellerseniz ileride telefonunuzda herhangi bir kaynaktan güncelleme alabilirsiniz. Uygulama işlevselliği değişebilir."</string> <string name="install_failed" msgid="5777824004474125469">"Uygulama yüklenmedi."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paketin yüklemesi engellendi."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Paket, mevcut bir paketle çakıştığından uygulama yüklenemedi."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Bilinmeyen uygulamalar bu kullanıcı tarafından yüklenemez"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Bu kullanıcının uygulama yüklemesine izin verilmiyor"</string> <string name="ok" msgid="7871959885003339302">"Tamam"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Yine de güncelle"</string> <string name="manage_applications" msgid="5400164782453975580">"Uygulamaları yönet"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Yer kalmadı"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> yüklenemedi. Boş alan açın ve yeniden deneyin."</string> diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml index ab07754827cd..e0e7d8841de4 100644 --- a/packages/PackageInstaller/res/values-uk/strings.xml +++ b/packages/PackageInstaller/res/values-uk/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Програму встановлено."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Установити цей додаток?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Оновити цей додаток?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Оновити цей додаток від <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗазвичай цей додаток отримує оновлення від <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Якщо встановити оновлення з іншого джерела, надалі на ваш телефон зможуть надходити оновлення з будь-яких джерел. Це може змінити функції додатка."</string> <string name="install_failed" msgid="5777824004474125469">"Програму не встановлено."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Встановлення пакета заблоковано."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Додаток не встановлено, оскільки пакет конфліктує з наявним пакетом."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Цей користувач не може встановлювати невідомі додатки"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Цей користувач не може встановлювати додатки"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Усе одно оновити"</string> <string name="manage_applications" msgid="5400164782453975580">"Керувати додатками"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Недостат. місця"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Програму <xliff:g id="APP_NAME">%1$s</xliff:g> неможливо встановити. Звільніть місце та повторіть спробу."</string> diff --git a/packages/PackageInstaller/res/values-ur/strings.xml b/packages/PackageInstaller/res/values-ur/strings.xml index 4f23cd2a1f10..b3b4c0d37ed1 100644 --- a/packages/PackageInstaller/res/values-ur/strings.xml +++ b/packages/PackageInstaller/res/values-ur/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"ایپ انسٹال ہو گئی۔"</string> <string name="install_confirm_question" msgid="7663733664476363311">"کیا آپ یہ ایپ انسٹال کرنا چاہتے ہیں؟"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"کیا آپ یہ ایپ اپ ڈیٹ کرنا چاہتے ہیں؟"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"اس ایپ کو <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> سے اپ ڈیٹ کریں؟\n\n اس ایپ کو عام طور پر <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> سے اپ ڈیٹس موصول ہوتی ہیں۔ کسی مختلف ذریعے سے اپ ڈیٹ کر کے، آپ اپنے فون پر کسی بھی ذریعے سے مستقبل کی اپ ڈیٹس حاصل کر سکتے ہیں۔ ایپ کی فعالیت تبدیل ہو سکتی ہے۔"</string> <string name="install_failed" msgid="5777824004474125469">"ایپ انسٹال نہیں ہوئی۔"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"پیکج کو انسٹال ہونے سے مسدود کر دیا گیا تھا۔"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"ایپ انسٹال نہیں ہوئی کیونکہ پیکج ایک موجودہ پیکیج سے متصادم ہے۔"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"یہ صارف نامعلوم ایپس کو انسٹال نہیں کر سکتا"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"اس صارف کو ایپس انسٹال کرنے کی اجازت نہیں ہے"</string> <string name="ok" msgid="7871959885003339302">"ٹھیک ہے"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"بہر حال اپ ڈیٹ کریں"</string> <string name="manage_applications" msgid="5400164782453975580">"ایپس منظم کریں"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"جگہ نہیں ہے"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو انسٹال نہیں کیا جا سکا۔ کچھ جگہ خالی کریں اور دوبارہ کوشش کریں۔"</string> diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml index 48d8681a2cd2..2993663c6829 100644 --- a/packages/PackageInstaller/res/values-uz/strings.xml +++ b/packages/PackageInstaller/res/values-uz/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Ilova o‘rnatildi."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Bu ilovani oʻrnatmoqchimisiz?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Bu ilova yangilansinmi?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Bu ilova <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> orqali yangilansinmi?\n\nBu ilova odatda <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> orqali yangilanishlar oladi. Boshqa manbadan yangilash orqali siz kelajakdagi yangilanishlarni telefoningizda istalgan manbadan olishingiz mumkin. Ilova funksiyalari oʻzgarishi mumkin."</string> <string name="install_failed" msgid="5777824004474125469">"Ilova o‘rnatilmadi."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Paket o‘rnatilishga qarshi bloklangan."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Paket mavjud paket bilan zid kelganligi uchun ilovani o‘rnatib bo‘lmadi."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Notanish ilovalarni bu foydalanuvchi tomonidan o‘rnatib bo‘lmaydi"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Bu foydalanuvchiga ilovalarni o‘rnatish uchun ruxsat berilmagan"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Baribir yangilansin"</string> <string name="manage_applications" msgid="5400164782453975580">"Ilovalarni boshqarish"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Joy qolmadi"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g> o‘rnatilmadi. Xotiradan biroz joy bo‘shating va qaytadan urining."</string> diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml index 4cc563da2ce3..f6ffa3a2efb7 100644 --- a/packages/PackageInstaller/res/values-vi/strings.xml +++ b/packages/PackageInstaller/res/values-vi/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Ứng dụng đã được cài đặt."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Bạn có muốn cài đặt ứng dụng này không?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Bạn có muốn cập nhật ứng dụng này không?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Cập nhật ứng dụng này của <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nỨng dụng này thường nhận thông tin cập nhật từ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Khi cập nhật từ một nguồn khác, trong tương lai, bạn có thể nhận thông tin cập nhật từ nguồn bất kỳ trên điện thoại của bạn. Chức năng ứng dụng có thể thay đổi."</string> <string name="install_failed" msgid="5777824004474125469">"Ứng dụng chưa được cài đặt."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Đã chặn cài đặt gói."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Chưa cài đặt được ứng dụng do gói xung đột với một gói hiện có."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Người dùng này không thể cài đặt ứng dụng không xác định"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Người dùng này không được phép cài đặt ứng dụng"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Vẫn cập nhật"</string> <string name="manage_applications" msgid="5400164782453975580">"Quản lý ứng dụng"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Hết dung lượng"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Không thể cài đặt <xliff:g id="APP_NAME">%1$s</xliff:g>. Hãy giải phóng dung lượng và thử lại."</string> diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml index b4bf413e6cb9..a59f94077786 100644 --- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml +++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"已安装应用。"</string> <string name="install_confirm_question" msgid="7663733664476363311">"要安装此应用吗?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此应用吗?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"要通过<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>更新此应用?\n\n此应用通常通过<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>接收更新。如果通过其他来源更新,手机未来可能会收到任何来源的更新。应用功能可能会变化。"</string> <string name="install_failed" msgid="5777824004474125469">"未安装应用。"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"系统已禁止安装该软件包。"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"应用未安装:软件包与现有软件包存在冲突。"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"该用户无法安装未知应用"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"此用户无权安装应用"</string> <string name="ok" msgid="7871959885003339302">"确定"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"仍然更新"</string> <string name="manage_applications" msgid="5400164782453975580">"管理应用"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"空间不足"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"无法安装<xliff:g id="APP_NAME">%1$s</xliff:g>。请释放一些存储空间并重试。"</string> diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml index 0c4ed6c7960e..6412eff878ae 100644 --- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml +++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string> <string name="install_confirm_question" msgid="7663733664476363311">"要安裝此應用程式嗎?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此應用程式嗎?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"要從「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新此應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新此應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string> <string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"套件已遭封鎖,無法安裝。"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"套件與現有的套件發生衝突,無法安裝應用程式。"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"此使用者無法安裝來源不明的應用程式"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"此使用者無法安裝應用程式"</string> <string name="ok" msgid="7871959885003339302">"確定"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"仍要更新"</string> <string name="manage_applications" msgid="5400164782453975580">"管理應用程式"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"儲存空間不足"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"無法安裝「<xliff:g id="APP_NAME">%1$s</xliff:g>」。請先騰出一些儲存空間,然後再試一次。"</string> diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml index 9b7bda6af6e5..2a87eb880df2 100644 --- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml +++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string> <string name="install_confirm_question" msgid="7663733664476363311">"要安裝這個應用程式嗎?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"要更新這個應用程式嗎?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新這個應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新這個應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string> <string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string> <string name="install_failed_blocked" msgid="8512284352994752094">"系統已封鎖這個套件,因此無法安裝。"</string> <string name="install_failed_conflict" msgid="3493184212162521426">"應用程式套件與現有套件衝突,因此未能完成安裝。"</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"這位使用者無法安裝不明的應用程式"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"這位使用者無法安裝應用程式"</string> <string name="ok" msgid="7871959885003339302">"確定"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"仍要更新"</string> <string name="manage_applications" msgid="5400164782453975580">"管理應用程式"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"空間不足"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"無法安裝「<xliff:g id="APP_NAME">%1$s</xliff:g>」。請先釋出部分空間,然後再試一次。"</string> diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml index 7317abc3d617..ca9c63b9e3a6 100644 --- a/packages/PackageInstaller/res/values-zu/strings.xml +++ b/packages/PackageInstaller/res/values-zu/strings.xml @@ -26,8 +26,7 @@ <string name="install_done" msgid="5987363587661783896">"Uhlelo lokusebenza olufakiwe."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Ingabe ufuna ukufaka le app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Ingabe ufuna ukubuyekeza le app?"</string> - <!-- no translation found for install_confirm_question_update_owner_reminder (3750986542284587290) --> - <skip /> + <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Buyekeza le app kusuka ku-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNgokuvamile le app ithola izibuyekezo kusuka ku-<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ngokubuyekeza kusuka kumthombo ohlukile, ungase uthole izibuyekezo zesikhathi esizayo kusuka kunoma yimuphi umthombo efonini yakho. Okwenziwa yi-app kungase kushintshe."</string> <string name="install_failed" msgid="5777824004474125469">"Uhlelo lokusebenza alufakiwe."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Iphakheji livinjiwe kusukela ekufakweni."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Uhlelo lokusebenza alufakiwe njengoba ukuphakheja kushayisana nephakheji elikhona."</string> @@ -43,8 +42,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Izinhlelo zokusebenza ezingaziwa azikwazi ukufakwa ilo msebenzisi"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Lo msebenzisi akavunyelwe ukufaka izinhlelo zokusebenza"</string> <string name="ok" msgid="7871959885003339302">"KULUNGILE"</string> - <!-- no translation found for update_anyway (8792432341346261969) --> - <skip /> + <string name="update_anyway" msgid="8792432341346261969">"Buyekeza noma kunjalo"</string> <string name="manage_applications" msgid="5400164782453975580">"Phatha izinhlelo zokusebenza"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Iphelelwe yisikhala"</string> <string name="out_of_space_dlg_text" msgid="8727714096031856231">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayikwazanga ukufakwa. Khulula isikhala bese uzama futhi."</string> diff --git a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java index f305fd35b7d9..e92157e7c867 100644 --- a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java +++ b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java @@ -47,7 +47,7 @@ import javax.tools.Diagnostic.Kind; * Annotation processor for {@link SearchIndexable} that generates {@link SearchIndexableResources} * subclasses. */ -@SupportedSourceVersion(SourceVersion.RELEASE_11) +@SupportedSourceVersion(SourceVersion.RELEASE_17) @SupportedAnnotationTypes({"com.android.settingslib.search.SearchIndexable"}) public class IndexableProcessor extends AbstractProcessor { diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java index 78b78101e64e..964e4b24d130 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java @@ -119,29 +119,15 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils { } final int restrictionSource = enforcingUsers.get(0).getUserRestrictionSource(); - final int adminUserId = enforcingUsers.get(0).getUserHandle().getIdentifier(); - if (restrictionSource == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) { - // Check if it is a profile owner of the user under consideration. - if (adminUserId == userId) { - return getProfileOwner(context, userRestriction, adminUserId); - } else { - // Check if it is a profile owner of a managed profile of the current user. - // Otherwise it is in a separate user and we return a default EnforcedAdmin. - final UserInfo parentUser = um.getProfileParent(adminUserId); - return (parentUser != null && parentUser.id == userId) - ? getProfileOwner(context, userRestriction, adminUserId) - : EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction); - } - } else if (restrictionSource == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { - // When the restriction is enforced by device owner, return the device owner admin only - // if the admin is for the {@param userId} otherwise return a default EnforcedAdmin. - return adminUserId == userId - ? getDeviceOwner(context, userRestriction) - : EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction); + if (restrictionSource == UserManager.RESTRICTION_SOURCE_SYSTEM) { + return null; } - // If the restriction is enforced by system then return null. - return null; + final EnforcedAdmin admin = getProfileOrDeviceOwner(context, userHandle); + if (admin != null) { + return admin; + } + return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction); } public static boolean hasBaseUserRestriction(Context context, diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 48d449dd7daa..5e8f3a18cbc0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -483,7 +483,10 @@ public class ApplicationsState { public AppEntry getEntry(String packageName, int userId) { if (DEBUG_LOCKING) Log.v(TAG, "getEntry about to acquire lock..."); synchronized (mEntriesMap) { - AppEntry entry = mEntriesMap.get(userId).get(packageName); + AppEntry entry = null; + if (mEntriesMap.contains(userId)) { + entry = mEntriesMap.get(userId).get(packageName); + } if (entry == null) { ApplicationInfo info = getAppInfoLocked(packageName, userId); if (info == null) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 04168ce6d79a..a3d632cfb82a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -940,7 +940,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> + getName() + ", groupId=" + mGroupId - + ", member= " + mMemberDevices + ")"; } @@ -1495,6 +1494,33 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } /** + * In order to show the preference for the whole group, we always set the main device as the + * first connected device in the coordinated set, and then switch the content of the main + * device and member devices. + * + * @param newMainDevice the new Main device which is from the previous main device's member + * list. + */ + public void switchMemberDeviceContent(CachedBluetoothDevice newMainDevice) { + // Backup from main device + final BluetoothDevice tmpDevice = mDevice; + final short tmpRssi = mRssi; + final boolean tmpJustDiscovered = mJustDiscovered; + // Set main device from sub device + release(); + mDevice = newMainDevice.mDevice; + mRssi = newMainDevice.mRssi; + mJustDiscovered = newMainDevice.mJustDiscovered; + + // Set sub device from backup + newMainDevice.release(); + newMainDevice.mDevice = tmpDevice; + newMainDevice.mRssi = tmpRssi; + newMainDevice.mJustDiscovered = tmpJustDiscovered; + fetchActiveDevices(); + } + + /** * Get cached bluetooth icon with description */ public Pair<Drawable, String> getDrawableWithDescription() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index d191b1e1c0e6..7b4c86207a2a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -464,59 +464,6 @@ public class CachedBluetoothDeviceManager { return !(mOngoingSetMemberPair == null) && mOngoingSetMemberPair.equals(device); } - /** - * In order to show the preference for the whole group, we always set the main device as the - * first connected device in the coordinated set, and then switch the relationship of the main - * device and member devices. - * - * @param newMainDevice the new Main device which is from the previous main device's member - * list. - */ - public void switchRelationshipFromMemberToMain(CachedBluetoothDevice newMainDevice) { - if (newMainDevice == null) { - log("switchRelationshipFromMemberToMain: input is null"); - return; - } - log("switchRelationshipFromMemberToMain: CachedBluetoothDevice list: " + mCachedDevices); - - final CachedBluetoothDevice finalNewMainDevice = newMainDevice; - int newMainGroupId = newMainDevice.getGroupId(); - CachedBluetoothDevice oldMainDevice = mCachedDevices.stream() - .filter(cachedDevice -> !cachedDevice.equals(finalNewMainDevice) - && cachedDevice.getGroupId() == newMainGroupId).findFirst().orElse(null); - boolean hasMainDevice = oldMainDevice != null; - Set<CachedBluetoothDevice> memberSet = - hasMainDevice ? oldMainDevice.getMemberDevice() : null; - boolean isMemberDevice = memberSet != null && memberSet.contains(newMainDevice); - if (!hasMainDevice || !isMemberDevice) { - log("switchRelationshipFromMemberToMain: " - + newMainDevice.getDevice().getAnonymizedAddress() - + " is not the member device."); - return; - } - - mCachedDevices.remove(oldMainDevice); - // When both LE Audio devices are disconnected, receiving member device - // connection. To switch content and dispatch to notify UI change - mBtManager.getEventManager().dispatchDeviceRemoved(oldMainDevice); - - for (CachedBluetoothDevice memberDeviceItem : memberSet) { - if (memberDeviceItem.equals(newMainDevice)) { - continue; - } - newMainDevice.addMemberDevice(memberDeviceItem); - } - memberSet.clear(); - newMainDevice.addMemberDevice(oldMainDevice); - - mCachedDevices.add(newMainDevice); - // It is necessary to do remove and add for updating the mapping on - // preference and device - mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice); - log("switchRelationshipFromMemberToMain: After change, CachedBluetoothDevice list: " - + mCachedDevices); - } - private void log(String msg) { if (DEBUG) { Log.d(TAG, msg); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java index 814c395865b1..20a6cd8e09ce 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java @@ -238,10 +238,14 @@ public class CsipDeviceManager { mainDevice.refresh(); return true; } else { - final CachedBluetoothDeviceManager deviceManager = - mBtManager.getCachedDeviceManager(); - deviceManager.switchRelationshipFromMemberToMain(cachedDevice); - cachedDevice.refresh(); + // When both LE Audio devices are disconnected, receiving member device + // connection. To switch content and dispatch to notify UI change + mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice); + mainDevice.switchMemberDeviceContent(cachedDevice); + mainDevice.refresh(); + // It is necessary to do remove and add for updating the mapping on + // preference and device + mBtManager.getEventManager().dispatchDeviceAdded(mainDevice); return true; } } @@ -262,10 +266,14 @@ public class CsipDeviceManager { for (CachedBluetoothDevice device: memberSet) { if (device.isConnected()) { log("set device: " + device + " as the main device"); - final CachedBluetoothDeviceManager deviceManager = - mBtManager.getCachedDeviceManager(); - deviceManager.switchRelationshipFromMemberToMain(device); - device.refresh(); + // Main device is disconnected and sub device is connected + // To copy data from sub device to main device + mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice); + cachedDevice.switchMemberDeviceContent(device); + cachedDevice.refresh(); + // It is necessary to do remove and add for updating the mapping on + // preference and device + mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice); return true; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java index 250187f210dc..df0e61833269 100644 --- a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java @@ -312,12 +312,6 @@ public class DataServiceUtils { "isFirstRemovableSubscription"; /** - * The name of the default SIM config column, - * {@see SubscriptionUtil#getDefaultSimConfig(Context, int)}. - */ - public static final String COLUMN_DEFAULT_SIM_CONFIG = "defaultSimConfig"; - - /** * The name of the default subscription selection column, * {@see SubscriptionUtil#getSubscriptionOrDefault(Context, int)}. */ @@ -349,32 +343,6 @@ public class DataServiceUtils { public static final String COLUMN_IS_AVAILABLE_SUBSCRIPTION = "isAvailableSubscription"; /** - * The name of the default voice subscription state column, see - * {@link SubscriptionManager#getDefaultVoiceSubscriptionId()}. - */ - public static final String COLUMN_IS_DEFAULT_VOICE_SUBSCRIPTION = - "isDefaultVoiceSubscription"; - - /** - * The name of the default sms subscription state column, see - * {@link SubscriptionManager#getDefaultSmsSubscriptionId()}. - */ - public static final String COLUMN_IS_DEFAULT_SMS_SUBSCRIPTION = "isDefaultSmsSubscription"; - - /** - * The name of the default data subscription state column, see - * {@link SubscriptionManager#getDefaultDataSubscriptionId()}. - */ - public static final String COLUMN_IS_DEFAULT_DATA_SUBSCRIPTION = - "isDefaultDataSubscription"; - - /** - * The name of the default subscription state column, see - * {@link SubscriptionManager#getDefaultSubscriptionId()}. - */ - public static final String COLUMN_IS_DEFAULT_SUBSCRIPTION = "isDefaultSubscription"; - - /** * The name of the active data subscription state column, see * {@link SubscriptionManager#getActiveDataSubscriptionId()}. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java index 23566f760444..c40388fee710 100644 --- a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java +++ b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java @@ -37,12 +37,10 @@ public class SubscriptionInfoEntity { String countryIso, boolean isEmbedded, int cardId, int portIndex, boolean isOpportunistic, @Nullable String groupUUID, int subscriptionType, String uniqueName, boolean isSubscriptionVisible, String formattedPhoneNumber, - boolean isFirstRemovableSubscription, String defaultSimConfig, - boolean isDefaultSubscriptionSelection, boolean isValidSubscription, - boolean isUsableSubscription, boolean isActiveSubscriptionId, - boolean isAvailableSubscription, boolean isDefaultVoiceSubscription, - boolean isDefaultSmsSubscription, boolean isDefaultDataSubscription, - boolean isDefaultSubscription, boolean isActiveDataSubscriptionId) { + boolean isFirstRemovableSubscription, boolean isDefaultSubscriptionSelection, + boolean isValidSubscription, boolean isUsableSubscription, + boolean isActiveSubscriptionId, boolean isAvailableSubscription, + boolean isActiveDataSubscriptionId) { this.subId = subId; this.simSlotIndex = simSlotIndex; this.carrierId = carrierId; @@ -62,16 +60,11 @@ public class SubscriptionInfoEntity { this.isSubscriptionVisible = isSubscriptionVisible; this.formattedPhoneNumber = formattedPhoneNumber; this.isFirstRemovableSubscription = isFirstRemovableSubscription; - this.defaultSimConfig = defaultSimConfig; this.isDefaultSubscriptionSelection = isDefaultSubscriptionSelection; this.isValidSubscription = isValidSubscription; this.isUsableSubscription = isUsableSubscription; this.isActiveSubscriptionId = isActiveSubscriptionId; this.isAvailableSubscription = isAvailableSubscription; - this.isDefaultVoiceSubscription = isDefaultVoiceSubscription; - this.isDefaultSmsSubscription = isDefaultSmsSubscription; - this.isDefaultDataSubscription = isDefaultDataSubscription; - this.isDefaultSubscription = isDefaultSubscription; this.isActiveDataSubscriptionId = isActiveDataSubscriptionId; } @@ -135,9 +128,6 @@ public class SubscriptionInfoEntity { @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_FIRST_REMOVABLE_SUBSCRIPTION) public boolean isFirstRemovableSubscription; - @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_DEFAULT_SIM_CONFIG) - public String defaultSimConfig; - @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_DEFAULT_SUBSCRIPTION_SELECTION) public boolean isDefaultSubscriptionSelection; @@ -154,18 +144,6 @@ public class SubscriptionInfoEntity { @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_AVAILABLE_SUBSCRIPTION) public boolean isAvailableSubscription; - @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_DEFAULT_VOICE_SUBSCRIPTION) - public boolean isDefaultVoiceSubscription; - - @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_DEFAULT_SMS_SUBSCRIPTION) - public boolean isDefaultSmsSubscription; - - @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_DEFAULT_DATA_SUBSCRIPTION) - public boolean isDefaultDataSubscription; - - @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_DEFAULT_SUBSCRIPTION) - public boolean isDefaultSubscription; - @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_ACTIVE_DATA_SUBSCRIPTION) public boolean isActiveDataSubscriptionId; @@ -207,16 +185,11 @@ public class SubscriptionInfoEntity { result = 31 * result + Boolean.hashCode(isSubscriptionVisible); result = 31 * result + formattedPhoneNumber.hashCode(); result = 31 * result + Boolean.hashCode(isFirstRemovableSubscription); - result = 31 * result + defaultSimConfig.hashCode(); result = 31 * result + Boolean.hashCode(isDefaultSubscriptionSelection); result = 31 * result + Boolean.hashCode(isValidSubscription); result = 31 * result + Boolean.hashCode(isUsableSubscription); result = 31 * result + Boolean.hashCode(isActiveSubscriptionId); result = 31 * result + Boolean.hashCode(isAvailableSubscription); - result = 31 * result + Boolean.hashCode(isDefaultVoiceSubscription); - result = 31 * result + Boolean.hashCode(isDefaultSmsSubscription); - result = 31 * result + Boolean.hashCode(isDefaultDataSubscription); - result = 31 * result + Boolean.hashCode(isDefaultSubscription); result = 31 * result + Boolean.hashCode(isActiveDataSubscriptionId); return result; } @@ -250,16 +223,11 @@ public class SubscriptionInfoEntity { && isSubscriptionVisible == info.isSubscriptionVisible && TextUtils.equals(formattedPhoneNumber, info.formattedPhoneNumber) && isFirstRemovableSubscription == info.isFirstRemovableSubscription - && TextUtils.equals(defaultSimConfig, info.defaultSimConfig) && isDefaultSubscriptionSelection == info.isDefaultSubscriptionSelection && isValidSubscription == info.isValidSubscription && isUsableSubscription == info.isUsableSubscription && isActiveSubscriptionId == info.isActiveSubscriptionId && isAvailableSubscription == info.isAvailableSubscription - && isDefaultVoiceSubscription == info.isDefaultVoiceSubscription - && isDefaultSmsSubscription == info.isDefaultSmsSubscription - && isDefaultDataSubscription == info.isDefaultDataSubscription - && isDefaultSubscription == info.isDefaultSubscription && isActiveDataSubscriptionId == info.isActiveDataSubscriptionId; } @@ -303,8 +271,6 @@ public class SubscriptionInfoEntity { .append(formattedPhoneNumber) .append(", isFirstRemovableSubscription = ") .append(isFirstRemovableSubscription) - .append(", defaultSimConfig = ") - .append(defaultSimConfig) .append(", isDefaultSubscriptionSelection = ") .append(isDefaultSubscriptionSelection) .append(", isValidSubscription = ") @@ -315,14 +281,6 @@ public class SubscriptionInfoEntity { .append(isActiveSubscriptionId) .append(", isAvailableSubscription = ") .append(isAvailableSubscription) - .append(", isDefaultVoiceSubscription = ") - .append(isDefaultVoiceSubscription) - .append(", isDefaultSmsSubscription = ") - .append(isDefaultSmsSubscription) - .append(", isDefaultDataSubscription = ") - .append(isDefaultDataSubscription) - .append(", isDefaultSubscription = ") - .append(isDefaultSubscription) .append(", isActiveDataSubscriptionId = ") .append(isActiveDataSubscriptionId) .append(")}"); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java index 1791dce6021f..4b3820eb0444 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java @@ -604,87 +604,4 @@ public class CachedBluetoothDeviceManagerTest { verify(mDevice2).setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED); verify(mDevice2).createBond(BluetoothDevice.TRANSPORT_LE); } - - @Test - public void switchRelationshipFromMemberToMain_switchesMainDevice_switchesSuccessful() { - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1); - CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2); - doReturn(CAP_GROUP2).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3); - CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); - CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3); - assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isFalse(); - assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isTrue(); - assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isFalse(); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue(); - - mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice2); - - assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isTrue(); - assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isFalse(); - assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isFalse(); - assertThat(cachedDevice2.getMemberDevice().contains(cachedDevice1)).isTrue(); - } - - @Test - public void switchRelationshipFromMemberToMain_moreMembersCase_switchesSuccessful() { - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1); - CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2); - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3); - CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); - CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue(); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue(); - - mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice2); - - assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isTrue(); - assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isFalse(); - assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isTrue(); - assertThat(cachedDevice2.getMemberDevice().contains(cachedDevice1)).isTrue(); - assertThat(cachedDevice2.getMemberDevice().contains(cachedDevice3)).isTrue(); - } - - @Test - public void switchRelationshipFromMemberToMain_inputDeviceIsMainDevice_doesNotChangelist() { - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1); - CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2); - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3); - CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); - CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3); - Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy(); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue(); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue(); - - mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice1); - - devices = mCachedDeviceManager.getCachedDevicesCopy(); - assertThat(devices).contains(cachedDevice1); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue(); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue(); - } - - @Test - public void switchRelationshipFromMemberToMain_inputDeviceNotInMemberList_doesNotChangelist() { - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1); - CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2); - doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3); - CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); - cachedDevice1.getMemberDevice().remove(cachedDevice2); - CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3); - Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy(); - - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isFalse(); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue(); - - mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice2); - - devices = mCachedDeviceManager.getCachedDevicesCopy(); - assertThat(devices).contains(cachedDevice1); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isFalse(); - assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue(); - } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index ff1af92d71fe..1c179f838586 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -1138,6 +1138,25 @@ public class CachedBluetoothDeviceTest { } @Test + public void switchMemberDeviceContent_switchMainDevice_switchesSuccessful() { + mCachedDevice.mRssi = RSSI_1; + mCachedDevice.mJustDiscovered = JUSTDISCOVERED_1; + mSubCachedDevice.mRssi = RSSI_2; + mSubCachedDevice.mJustDiscovered = JUSTDISCOVERED_2; + mCachedDevice.addMemberDevice(mSubCachedDevice); + + mCachedDevice.switchMemberDeviceContent(mSubCachedDevice); + + assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2); + assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2); + assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice); + assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1); + assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1); + assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice); + assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue(); + } + + @Test public void isConnectedHearingAidDevice_isConnectedAshaHearingAidDevice_returnTrue() { when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index b93cc752d783..59cd7a051fad 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -23,8 +23,10 @@ <bool name="def_airplane_mode_on">false</bool> <bool name="def_theater_mode_on">false</bool> <!-- Comma-separated list of bluetooth, wifi, and cell. --> - <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string> - <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string> + <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,uwb,wifi,wimax</string> + <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi</string> + <string name="def_satellite_mode_radios" translatable="false"></string> + <integer name="def_satellite_mode_enabled" translatable="false">0</integer> <string name="def_bluetooth_disabled_profiles" translatable="false">0</string> <bool name="def_auto_time">true</bool> <bool name="def_auto_time_zone">true</bool> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 74774167caa0..ed5654d4f259 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -2413,6 +2413,12 @@ class DatabaseHelper extends SQLiteOpenHelper { loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_RADIOS, R.string.def_airplane_mode_radios); + loadStringSetting(stmt, Global.SATELLITE_MODE_RADIOS, + R.string.def_satellite_mode_radios); + + loadIntegerSetting(stmt, Global.SATELLITE_MODE_ENABLED, + R.integer.def_satellite_mode_enabled); + loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, R.string.airplane_mode_toggleable_radios); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 721b3c49b17c..5a8c59489ec8 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2311,7 +2311,7 @@ public class SettingsProvider extends ContentProvider { @NonNull Set<String> flags) { boolean hasAllowlistPermission = context.checkCallingOrSelfPermission( - Manifest.permission.ALLOWLISTED_WRITE_DEVICE_CONFIG) + Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG) == PackageManager.PERMISSION_GRANTED; boolean hasWritePermission = context.checkCallingOrSelfPermission( @@ -2331,7 +2331,7 @@ public class SettingsProvider extends ContentProvider { } } else { throw new SecurityException("Permission denial to mutate flag, must have root, " - + "WRITE_DEVICE_CONFIG, or ALLOWLISTED_WRITE_DEVICE_CONFIG"); + + "WRITE_DEVICE_CONFIG, or WRITE_ALLOWLISTED_DEVICE_CONFIG"); } } @@ -3739,7 +3739,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 215; + private static final int SETTINGS_VERSION = 216; private final int mUserId; @@ -5737,6 +5737,31 @@ public class SettingsProvider extends ContentProvider { currentVersion = 215; } + if (currentVersion == 215) { + // Version 215: default |def_airplane_mode_radios| and + // |airplane_mode_toggleable_radios| changed to remove NFC & add UWB. + final SettingsState globalSettings = getGlobalSettingsLocked(); + final String oldApmRadiosValue = globalSettings.getSettingLocked( + Settings.Global.AIRPLANE_MODE_RADIOS).getValue(); + if (TextUtils.equals("cell,bluetooth,wifi,nfc,wimax", oldApmRadiosValue)) { + globalSettings.insertSettingOverrideableByRestoreLocked( + Settings.Global.AIRPLANE_MODE_RADIOS, + getContext().getResources().getString( + R.string.def_airplane_mode_radios), + null, true, SettingsState.SYSTEM_PACKAGE_NAME); + } + final String oldApmToggleableRadiosValue = globalSettings.getSettingLocked( + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS).getValue(); + if (TextUtils.equals("bluetooth,wifi,nfc", oldApmToggleableRadiosValue)) { + globalSettings.insertSettingOverrideableByRestoreLocked( + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, + getContext().getResources().getString( + R.string.airplane_mode_toggleable_radios), + null, true, SettingsState.SYSTEM_PACKAGE_NAME); + } + currentVersion = 216; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index a9d14641af9a..19f1a86ec90c 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -114,6 +114,8 @@ public class SettingsBackupTest { Settings.Global.ADD_USERS_WHEN_LOCKED, Settings.Global.AIRPLANE_MODE_ON, Settings.Global.AIRPLANE_MODE_RADIOS, + Settings.Global.SATELLITE_MODE_RADIOS, + Settings.Global.SATELLITE_MODE_ENABLED, Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, Settings.Global.ALWAYS_FINISH_ACTIVITIES, @@ -271,7 +273,6 @@ 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.STYLUS_HANDWRITING_ENABLED, Settings.Global.STYLUS_EVER_USED, Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT, Settings.Global.ENABLE_MULTI_SLOT_TIMEOUT_MILLIS, @@ -420,6 +421,7 @@ public class SettingsBackupTest { Settings.Global.RADIO_NFC, Settings.Global.RADIO_WIFI, Settings.Global.RADIO_WIMAX, + Settings.Global.RADIO_UWB, Settings.Global.REMOVE_GUEST_ON_EXIT, Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS, Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT, @@ -782,6 +784,7 @@ public class SettingsBackupTest { Settings.Secure.SMS_DEFAULT_APPLICATION, Settings.Secure.SPELL_CHECKER_ENABLED, // Intentionally removed in Q Settings.Secure.STYLUS_BUTTONS_ENABLED, + Settings.Secure.STYLUS_HANDWRITING_ENABLED, Settings.Secure.TRUST_AGENTS_INITIALIZED, Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED, Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 4c48f0e63b16..fedfb43535cc 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -148,7 +148,7 @@ <uses-permission android:name="android.permission.LOCATION_BYPASS" /> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> - <uses-permission android:name="android.permission.ALLOWLISTED_WRITE_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG" /> <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" /> diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml index 666d254c2f50..42b635a691e4 100644 --- a/packages/Shell/res/values-hi/strings.xml +++ b/packages/Shell/res/values-hi/strings.xml @@ -40,7 +40,7 @@ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string> <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"गड़बड़ी की रिपोर्ट <xliff:g id="ID">#%d</xliff:g> की पूरी जानकारी"</string> <string name="bugreport_info_name" msgid="4414036021935139527">"फ़ाइल नाम"</string> - <string name="bugreport_info_title" msgid="2306030793918239804">"गड़बड़ी का शीर्षक"</string> + <string name="bugreport_info_title" msgid="2306030793918239804">"गड़बड़ी का टाइटल"</string> <string name="bugreport_info_description" msgid="5072835127481627722">"गड़बड़ी का सारांश"</string> <string name="save" msgid="4781509040564835759">"सेव करें"</string> <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"गड़बड़ी की रिपोर्ट शेयर करें"</string> diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index d92e65c3c581..ff570524ca0e 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -947,18 +947,6 @@ android:visibleToInstantApps="true"> </activity> - <activity android:name=".user.UserSwitcherActivity" - android:label="@string/accessibility_multi_user_switch_switcher" - android:theme="@style/Theme.UserSwitcherActivity" - android:excludeFromRecents="true" - android:showWhenLocked="true" - android:showForAllUsers="true" - android:finishOnTaskLaunch="true" - android:lockTaskMode="always" - android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" - android:visibleToInstantApps="true"> - </activity> - <receiver android:name=".controls.management.ControlsRequestReceiver" android:exported="true"> <intent-filter> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/README.md b/packages/SystemUI/accessibility/accessibilitymenu/README.md new file mode 100644 index 000000000000..b7fc363d4a8c --- /dev/null +++ b/packages/SystemUI/accessibility/accessibilitymenu/README.md @@ -0,0 +1,40 @@ +The Accessibility Menu is an accessibility service +that presents a large on-screen menu to control your Android device. +This service can be enabled from the Accessibility page in the Settings app. +You can control gestures, hardware buttons, navigation, and more. From the menu, you can: + +- Take screenshots +- Lock your screen +- Open the device's voice assistant +- Open Quick Settings and Notifications +- Turn volume up or down +- Turn brightness up or down + +The UI consists of a `ViewPager` populated by multiple pages of shortcut buttons. +In the settings for the menu, there is an option to display the buttons in a 3x3 grid per page, +or a 2x2 grid with larger buttons. + +Upon activation, most buttons will close the menu while performing their function. +The exception to this are buttons that adjust a value, like volume or brightness, +where the user is likely to want to press the button multiple times. +In addition, touching other parts of the screen or locking the phone through other means +should dismiss the menu. + +A majority of the shortcuts correspond directly to an existing accessibility service global action +(see `AccessibilityService#performGlobalAction()` constants) that is performed when pressed. +Shortcuts that navigate to a different menu, such as Quick Settings, use an intent to do so. +Shortcuts that adjust brightness or volume interface directly with +`DisplayManager` & `AudioManager` respectively. + +To add a new shortcut: + +1. Add a value for the new shortcut to the `ShortcutId` enum in `A11yMenuShortcut`. +2. Put an entry for the enum value into the `sShortcutResource` `HashMap` in `A11yMenuShortcut`. +This will require resources for a drawable icon, a color for the icon, +the displayed name of the shortcut and the desired text-to-speech output. +3. Add the enum value to the `SHORTCUT_LIST_DEFAULT` & `LARGE_SHORTCUT_LIST_DEFAULT` arrays +in `A11yMenuOverlayLayout`. +4. For functionality, add a code block to the if-else chain in +`AccessibilityMenuService.handleClick()`, detailing the effect of the shortcut. +If you don't want the shortcut to close the menu, +include a return statement at the end of the code block. diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml index d25970cc6abf..eb65a77072d9 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Toeganklikheidinstellings"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volumekontroles"</string> <string name="power_label" msgid="7699720321491287839">"Krag"</string> <string name="power_utterance" msgid="7444296686402104807">"Kragopsies"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Onlangse programme"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-am/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-am/strings.xml index fa189899e815..f215e857bb27 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-am/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-am/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"የተደራሽነት ምናሌ"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"የተደራሽነት ምናሌ መሣሪያዎን ለመቆጣጠር ትልቅ የማያ ገጽ ላይ ምናሌን ያቀርባል። የእርስዎን መሣሪያ መቆለፍ፣ ድምፅን እና ብሩህነትን መቆጣጠር፣ ቅጽበታዊ ገጽ ዕይታዎችን ማንሳት እና ተጨማሪ ነገሮችን ማድረግ ይችላሉ።"</string> <string name="assistant_label" msgid="6796392082252272356">"ረዳት"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"ረዳት"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"የተደራሽነት ቅንብሮች"</string> - <string name="volume_label" msgid="3682221827627150574">"ድምፅ"</string> - <string name="volume_utterance" msgid="408291570329066290">"የድምጽ መቆጣጠሪያዎች"</string> <string name="power_label" msgid="7699720321491287839">"ኃይል"</string> <string name="power_utterance" msgid="7444296686402104807">"የኃይል አማራጮች"</string> <string name="recent_apps_label" msgid="6583276995616385847">"የቅርብ ጊዜ መተግበሪያዎች"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ar/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ar/strings.xml index 89e42a3bc015..4560425ca5a2 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ar/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ar/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"قائمة \"تسهيل الاستخدام\""</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"قائمة \"تسهيل الاستخدام\" هي قائمة كبيرة تظهر على الشاشة وتتيح لك التحكّم في جهازك. يمكنك من خلال هذه القائمة قفل جهازك والتحكّم في مستوى الصوت والسطوع وتسجيل لقطات الشاشة وغير ذلك."</string> <string name="assistant_label" msgid="6796392082252272356">"مساعِد"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"مساعد Google"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"إعدادات \"سهولة الاستخدام\""</string> - <string name="volume_label" msgid="3682221827627150574">"مستوى الصوت"</string> - <string name="volume_utterance" msgid="408291570329066290">"عناصر التحكم في مستوى الصوت"</string> <string name="power_label" msgid="7699720321491287839">"زر التشغيل"</string> <string name="power_utterance" msgid="7444296686402104807">"خيارات التشغيل"</string> <string name="recent_apps_label" msgid="6583276995616385847">"التطبيقات المستخدمة مؤخرًا"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-as/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-as/strings.xml index 0528f39116b8..ec7beb355767 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-as/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-as/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"সাধ্য সুবিধাসমূহৰ মেনু"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"সাধ্য সুবিধাৰ মেনুখনে আপোনাৰ ডিভাইচটো নিয়ন্ত্ৰণ কৰিবলৈ স্ক্ৰীনত এখন ডাঙৰ মেনু দেখুৱায়। আপুনি নিজৰ ডিভাইচটো লক কৰিব পাৰে, ভলিউম আৰু উজ্জ্বলতা নিয়ন্ত্ৰণ কৰিব পাৰে, স্ক্ৰীনশ্বট ল’ব পাৰে আৰু বহুতো কাম কৰিব পাৰে।"</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"সাধ্য সুবিধাৰ ছেটিং"</string> - <string name="volume_label" msgid="3682221827627150574">"ভলিউম"</string> - <string name="volume_utterance" msgid="408291570329066290">"ভলিউমৰ নিয়ন্ত্ৰণসমূহ"</string> <string name="power_label" msgid="7699720321491287839">"অন/অফ"</string> <string name="power_utterance" msgid="7444296686402104807">"অন/অফ বুটামৰ বিকল্পসমূহ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"শেহতীয়া এপসমূহ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-az/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-az/strings.xml index f366f3d7bbba..49c26bfe5e6d 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-az/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-az/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Əlçatımlılıq Menyusu"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Əlçatımlılıq Menyusu cihazınızı idarə etmək üçün böyük geniş ekran menyusu təqdim edir. Cihazı kilidləyə, səs səviyyəsinə və parlaqlığa nəzarət edə, skrinşotlar çəkə və s. edə bilərsiniz."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Əlçatımlılıq Ayarları"</string> - <string name="volume_label" msgid="3682221827627150574">"Səs"</string> - <string name="volume_utterance" msgid="408291570329066290">"Səs nəzarətləri"</string> <string name="power_label" msgid="7699720321491287839">"Yandırıb-söndürmə düyməsi"</string> <string name="power_utterance" msgid="7444296686402104807">"Qidalanma düyməsi seçimləri"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Son tətbiqlər"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-b+sr+Latn/strings.xml index fa2ca2415811..3ec174987e7e 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-b+sr+Latn/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Meni Pristupačnost"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Meni Pristupačnost pruža veliki meni na ekranu za kontrolu uređaja. Možete da zaključate uređaj, kontrolišete jačinu zvuka i osvetljenost, pravite snimke ekrana i drugo."</string> <string name="assistant_label" msgid="6796392082252272356">"Pomoćnik"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Pomoćnik"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Podešavanja pristupačnosti"</string> - <string name="volume_label" msgid="3682221827627150574">"Jačina zvuka"</string> - <string name="volume_utterance" msgid="408291570329066290">"Kontrole jačine zvuka"</string> <string name="power_label" msgid="7699720321491287839">"Napajanje"</string> <string name="power_utterance" msgid="7444296686402104807">"Opcije napajanja"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Nedavne aplikacije"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-be/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-be/strings.xml index 53ce5fa45be4..572d25cae6fa 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-be/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-be/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Спецыяльныя магчымасці"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Меню спецыяльных магчымасцей – гэта вялікае экраннае меню для кіравання прыладай. Вы можаце блакіраваць прыладу, рэгуляваць гучнасць і яркасць, рабіць здымкі экрана і выконваць іншыя дзеянні."</string> <string name="assistant_label" msgid="6796392082252272356">"Памочнік"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Памочнік"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Налады спецыяльных магчымасцей"</string> - <string name="volume_label" msgid="3682221827627150574">"Гучнасць"</string> - <string name="volume_utterance" msgid="408291570329066290">"Рэгулятары гучнасці"</string> <string name="power_label" msgid="7699720321491287839">"Кнопка сілкавання"</string> <string name="power_utterance" msgid="7444296686402104807">"Налады кнопкі сілкавання"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Нядаўнія праграмы"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml index 709a6e0d27f6..165b9276adce 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Асистент"</string> <string name="assistant_utterance" msgid="65509599221141377">"Асистент"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Настройки за достъпност"</string> - <string name="volume_label" msgid="3682221827627150574">"Сила на звука"</string> - <string name="volume_utterance" msgid="408291570329066290">"Контроли за силата на звука"</string> <string name="power_label" msgid="7699720321491287839">"Захранване"</string> <string name="power_utterance" msgid="7444296686402104807">"Опции за захранването"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Скорошни приложения"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml index b5d659350108..9a0ebef6c639 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"অ্যাক্সেসিবিলিটি মেনু"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"আপনার ডিভাইস নিয়ন্ত্রণ করতে, \'অ্যাক্সেসিবিলিটি মেনু\' একটি বড় অন-স্ক্রিন মেনু দেখায়। আপনি ফোন লক, ভলিউম ও উজ্জ্বলতা নিয়ন্ত্রণ, স্ক্রিনশট নেওয়া এবং আরও অনেক কিছু করতে পারবেন।"</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"অ্যাক্সেসিবিলিটি সেটিংস"</string> - <string name="volume_label" msgid="3682221827627150574">"ভলিউম"</string> - <string name="volume_utterance" msgid="408291570329066290">"ভলিউম নিয়ন্ত্রণ"</string> <string name="power_label" msgid="7699720321491287839">"পাওয়ার"</string> <string name="power_utterance" msgid="7444296686402104807">"পাওয়ারের বিকল্পগুলি"</string> <string name="recent_apps_label" msgid="6583276995616385847">"সাম্প্রতিক অ্যাপ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bs/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bs/strings.xml index 227186b9ee2c..03a3436fa731 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bs/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bs/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Asistent"</string> <string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Postavke pristupačnosti"</string> - <string name="volume_label" msgid="3682221827627150574">"Jačina zvuka"</string> - <string name="volume_utterance" msgid="408291570329066290">"Kontrole jačine zvuka"</string> <string name="power_label" msgid="7699720321491287839">"Napajanje"</string> <string name="power_utterance" msgid="7444296686402104807">"Opcije napajanja"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Nedavne aplikacije"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ca/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ca/strings.xml index 08a301ce5e13..1c4f5a2ef498 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ca/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ca/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menú d\'accessibilitat"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"El menú d\'accessibilitat t\'ofereix un menú gran en pantalla perquè controlis el dispositiu. Pots bloquejar-lo, controlar-ne el volum i la brillantor, fer captures de pantalla i molt més."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Configuració d\'accessibilitat"</string> - <string name="volume_label" msgid="3682221827627150574">"Volum"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controls de volum"</string> <string name="power_label" msgid="7699720321491287839">"Botó d\'engegada"</string> <string name="power_utterance" msgid="7444296686402104807">"Opcions d\'engegada"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Aplicacions recents"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml index 796a3d5bf003..c0d9d4566e6f 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-cs/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Asistent"</string> <string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Nastavení usnadnění přístupu"</string> - <string name="volume_label" msgid="3682221827627150574">"Hlasitost"</string> - <string name="volume_utterance" msgid="408291570329066290">"Ovládání hlasitosti"</string> <string name="power_label" msgid="7699720321491287839">"Vypínač"</string> <string name="power_utterance" msgid="7444296686402104807">"Možnosti napájení"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Poslední aplikace"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-da/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-da/strings.xml index 6cde7a1fd6b4..d801298ba973 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-da/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-da/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menuen Hjælpefunktioner"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Menuen Hjælpefunktioner giver dig en stor menu på skærmen, som du kan bruge til at styre din enhed. Du kan låse din enhed, justere lyd- og lysstyrken, tage screenshots og meget mere."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Indstillinger for hjælpefunktioner"</string> - <string name="volume_label" msgid="3682221827627150574">"Lydstyrke"</string> - <string name="volume_utterance" msgid="408291570329066290">"Lydstyrkeknapper"</string> <string name="power_label" msgid="7699720321491287839">"Afbryderknap"</string> <string name="power_utterance" msgid="7444296686402104807">"Indstillinger for afbryderknappen"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Seneste apps"</string> @@ -23,9 +20,9 @@ <string name="brightness_down_label" msgid="7115662941913272072">"Lysstyrke ned"</string> <string name="previous_button_content_description" msgid="840869171117765966">"Gå til forrige skærm"</string> <string name="next_button_content_description" msgid="6810058269847364406">"Gå til næste skærm"</string> - <string name="accessibility_menu_description" msgid="4458354794093858297">"Menuen Hjælpefunktioner giver dig en stor menu på skærmen, som bruges til at styre din enhed. Du kan låse din enhed, justere lyd- og lysstyrken, tage screenshots og meget mere."</string> + <string name="accessibility_menu_description" msgid="4458354794093858297">"Menuen Hjælpefunktioner giver dig en stor menu på skærmen, som du kan bruge til at styre din enhed. Du kan låse din enhed, justere lyd- og lysstyrken, tage screenshots og meget mere."</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"Styr enheden via den store menu"</string> - <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Indstillinger for menuen Hjælpefunktioner"</string> + <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Indst. for menuen Hjælpefunktioner"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Store knapper"</string> <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Forstør knapperne i menuen Hjælpefunktioner"</string> <string name="pref_help_title" msgid="6871558837025010641">"Hjælp"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml index 7b94d9826702..7f7df4f8c68c 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menü für Bedienungshilfen"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Über das Menü „Bedienungshilfen“ lässt sich ein großes Menü zur Bedienung deines Geräts auf dem Bildschirm öffnen. Du kannst beispielsweise das Gerät sperren, die Lautstärke und Helligkeit anpassen und Screenshots machen."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Einstellungen für Bedienungshilfen"</string> - <string name="volume_label" msgid="3682221827627150574">"Lautstärke"</string> - <string name="volume_utterance" msgid="408291570329066290">"Lautstärketasten"</string> <string name="power_label" msgid="7699720321491287839">"Ein/Aus"</string> <string name="power_utterance" msgid="7444296686402104807">"Optionen für Ein-/Aus-Taste"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Kürzlich geöffnete Apps"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml index e5f7cd471ecf..c51c9afa07cc 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Μενού προσβασιμότητας"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Το μενού προσβασιμότητας παρέχει ένα μεγάλο μενού στην οθόνη για να ελέγχετε τη συσκευή σας. Μπορείτε να κλειδώνετε τη συσκευή, να ελέγχετε την ένταση ήχου και τη φωτεινότητα, να λαμβάνετε στιγμιότυπα οθόνης και άλλα."</string> <string name="assistant_label" msgid="6796392082252272356">"Βοηθός"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Βοηθός"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Ρυθμίσεις προσβασιμότητας"</string> - <string name="volume_label" msgid="3682221827627150574">"Ένταση"</string> - <string name="volume_utterance" msgid="408291570329066290">"Πλήκτρα έντασης ήχου"</string> <string name="power_label" msgid="7699720321491287839">"Κουμπί λειτουργίας"</string> <string name="power_utterance" msgid="7444296686402104807">"Επιλογές λειτουργίας"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Πρόσφατες εφαρμογές"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rAU/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rAU/strings.xml index 04b18dd82200..b09c34ddd480 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rAU/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Accessibility Settings"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volume controls"</string> <string name="power_label" msgid="7699720321491287839">"Power"</string> <string name="power_utterance" msgid="7444296686402104807">"Power options"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Recent apps"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rCA/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rCA/strings.xml index 2b300620345e..5fc3afdf1afc 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rCA/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Accessibility Settings"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volume controls"</string> <string name="power_label" msgid="7699720321491287839">"Power"</string> <string name="power_utterance" msgid="7444296686402104807">"Power options"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Recent apps"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rGB/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rGB/strings.xml index 04b18dd82200..b09c34ddd480 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rGB/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Accessibility Settings"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volume controls"</string> <string name="power_label" msgid="7699720321491287839">"Power"</string> <string name="power_utterance" msgid="7444296686402104807">"Power options"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Recent apps"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rIN/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rIN/strings.xml index 04b18dd82200..b09c34ddd480 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rIN/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Accessibility Settings"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volume controls"</string> <string name="power_label" msgid="7699720321491287839">"Power"</string> <string name="power_utterance" msgid="7444296686402104807">"Power options"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Recent apps"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rXC/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rXC/strings.xml index 8ab2c526b7d8..fec60d5f84b9 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rXC/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Accessibility Settings"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volume controls"</string> <string name="power_label" msgid="7699720321491287839">"Power"</string> <string name="power_utterance" msgid="7444296686402104807">"Power options"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Recent apps"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-es-rUS/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-es-rUS/strings.xml index f7628eb5b3a8..03c235bafaa4 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-es-rUS/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menú de Accesibilidad"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"El menú de Accesibilidad es un menú de gran tamaño que se muestra en la pantalla y te permite controlar tu dispositivo. Puedes bloquearlo, controlar el volumen y el brillo, realizar capturas de pantalla y mucho más."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistente"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistente"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Configuración de accesibilidad"</string> - <string name="volume_label" msgid="3682221827627150574">"Volumen"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controles de volumen"</string> <string name="power_label" msgid="7699720321491287839">"Encendido"</string> <string name="power_utterance" msgid="7444296686402104807">"Opciones de encendido"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Apps recientes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml index 50c93f7d2a5e..a00ba8a0d903 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menú de accesibilidad"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"El menú de accesibilidad es un menú de gran tamaño que se muestra en pantalla para controlar tu dispositivo. Puedes bloquear el dispositivo, controlar el volumen y el brillo, hacer capturas de pantalla y más."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistente"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistente"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Ajustes de accesibilidad"</string> - <string name="volume_label" msgid="3682221827627150574">"Volumen"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controles de volumen"</string> <string name="power_label" msgid="7699720321491287839">"Encender"</string> <string name="power_utterance" msgid="7444296686402104807">"Opciones de encendido"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Aplicaciones recientes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-et/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-et/strings.xml index 790d06031f90..8ba020648c9b 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-et/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-et/strings.xml @@ -2,13 +2,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="accessibility_menu_service_name" msgid="730136711554740131">"Juurdepääsetavuse menüü"</string> - <string name="accessibility_menu_intro" msgid="3164193281544042394">"Juurdepääsetavuse menüü on suur ekraanil kuvatav menüü, mille abil oma seadet hallata. Saate oma seadme lukustada, hallata helitugevust ja heledust, jäädvustada ekraanipilte ning teha muudki."</string> + <string name="accessibility_menu_intro" msgid="3164193281544042394">"Juurdepääsetavuse menüü on suur ekraanil kuvatav menüü, mille abil oma seadet hallata. Saate oma seadme lukustada, hallata helitugevust ja eredust, jäädvustada ekraanipilte ning teha muudki."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> - <string name="a11y_settings_label" msgid="3977714687248445050">"Juurdepääsetavuse seaded"</string> - <string name="volume_label" msgid="3682221827627150574">"Helitugevus"</string> - <string name="volume_utterance" msgid="408291570329066290">"Helitugevuse juhtnupud"</string> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> + <string name="a11y_settings_label" msgid="3977714687248445050">"Juurdepääsetavuse seaded"</string> <string name="power_label" msgid="7699720321491287839">"Toitenupp"</string> <string name="power_utterance" msgid="7444296686402104807">"Toitevalikud"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Hiljutised rakendused"</string> @@ -23,11 +20,11 @@ <string name="brightness_down_label" msgid="7115662941913272072">"Vähenda eredust"</string> <string name="previous_button_content_description" msgid="840869171117765966">"Eelmise ekraanikuva avamine"</string> <string name="next_button_content_description" msgid="6810058269847364406">"Järgmise ekraanikuva avamine"</string> - <string name="accessibility_menu_description" msgid="4458354794093858297">"Juurdepääsetavuse menüü on suur ekraanil kuvatav menüü, mille abil oma seadet hallata. Saate oma seadme lukustada, hallata helitugevust ja heledust, jäädvustada ekraanipilte ning teha muudki."</string> + <string name="accessibility_menu_description" msgid="4458354794093858297">"Juurdepääsetavuse menüü on suur ekraanil kuvatav menüü, mille abil oma seadet hallata. Saate oma seadme lukustada, hallata helitugevust ja eredust, jäädvustada ekraanipilte ning teha muudki."</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"Seadme juhtimine suure menüü kaudu"</string> <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Juurdepääsetavuse menüü seaded"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Suured nupud"</string> - <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Juurdepääsetavusmenüü nuppude suuruse suurendamine"</string> + <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Juurdepääsetavuse menüü nuppude suurendamine"</string> <string name="pref_help_title" msgid="6871558837025010641">"Abi"</string> <string name="brightness_percentage_label" msgid="7391554573977867369">"Eredus on <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string> <string name="music_volume_percentage_label" msgid="398635599662604706">"Muusika helitugevus on <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml index 98c0146656bb..28b560a71de7 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Erabilerraztasun-menua"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Erabilerraztasun-menuari esker, tamaina handiko menu bat izango duzu pantailan; menu horren bidez, gailua kontrolatzeko aukera izango duzu. Besteak beste, hauek egin ahalko dituzu: gailua blokeatu; bolumena eta distira kontrolatu, eta pantaila-argazkiak egin."</string> <string name="assistant_label" msgid="6796392082252272356">"Laguntzailea"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Laguntzailea"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Erabilerraztasun-ezarpenak"</string> - <string name="volume_label" msgid="3682221827627150574">"Bolumena"</string> - <string name="volume_utterance" msgid="408291570329066290">"Bolumena kontrolatzeko aukerak"</string> <string name="power_label" msgid="7699720321491287839">"Bateria"</string> <string name="power_utterance" msgid="7444296686402104807">"Bateria kontrolatzeko aukerak"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Azken aplikazioak"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml index c922b2478b6f..9e1e8b20766b 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fa/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"منوی دسترسپذیری"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"«منوی دسترسپذیری» منوی بزرگی را روی صفحه برای کنترل دستگاه ارائه میدهد. میتوانید دستگاه را قفل کنید، میزان صدا و روشنایی را کنترل کنید، نماگرفت ثبت کنید، و کارهای بیشتری انجام دهید."</string> <string name="assistant_label" msgid="6796392082252272356">"دستیار"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"دستیار"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"تنظیمات دسترسپذیری"</string> - <string name="volume_label" msgid="3682221827627150574">"میزان صدا"</string> - <string name="volume_utterance" msgid="408291570329066290">"کنترلهای میزان صدا"</string> <string name="power_label" msgid="7699720321491287839">"نیرو"</string> <string name="power_utterance" msgid="7444296686402104807">"گزینههای نیرو"</string> <string name="recent_apps_label" msgid="6583276995616385847">"برنامههای اخیر"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml index b9926a523e0f..8ab880c14d15 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Saavutettavuusvalikko"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Saavutettavuusvalikko on suuri näyttövalikko, josta voit ohjata laitettasi. Voit esimerkiksi lukita laitteen, säätää äänenvoimakkuutta ja kirkkautta sekä ottaa kuvakaappauksia."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Esteettömyysasetukset"</string> - <string name="volume_label" msgid="3682221827627150574">"Äänenvoimakkuus"</string> - <string name="volume_utterance" msgid="408291570329066290">"Äänenvoimakkuuden hallinta"</string> <string name="power_label" msgid="7699720321491287839">"Virta"</string> <string name="power_utterance" msgid="7444296686402104807">"Virta-asetukset"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Viimeaikaiset sovellukset"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml index 9ac0f0412280..993a9fc740a4 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu d\'accessibilité"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Le menu Accessibilité propose un grand espace à l\'écran à l\'aide duquel vous pouvez contrôler votre appareil. Utilisez-le pour verrouiller votre appareil, régler le volume et la luminosité, prendre des captures d\'écran et plus."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Paramètres d\'accessibilité"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Commandes de volume"</string> <string name="power_label" msgid="7699720321491287839">"Alimentation"</string> <string name="power_utterance" msgid="7444296686402104807">"Options d\'alimentation"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Applis récentes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr/strings.xml index 774210d6f7db..10c6169b3365 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu d\'accessibilité"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Le menu d\'accessibilité s\'affiche en grand sur votre écran pour vous permettre de contrôler votre appareil. Vous pouvez verrouiller votre appareil, ajuster le volume et la luminosité, réaliser des captures d\'écran, et plus encore."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Accessibilité"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Commandes de volume"</string> <string name="power_label" msgid="7699720321491287839">"Marche/Arrêt"</string> <string name="power_utterance" msgid="7444296686402104807">"Options du bouton Marche/Arrêt"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Applis récentes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-gl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-gl/strings.xml index 4d6656b8c135..ceb8fe866307 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-gl/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-gl/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menú de accesibilidade"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"O menú de accesibilidade é un panel grande que aparece na pantalla co que podes controlar o dispositivo. Permíteche realizar varias accións, entre elas, bloquear o dispositivo, controlar o volume, axustar o brillo e facer capturas de pantalla."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistente"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistente"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Accesibilidade (configuración)"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controis de volume"</string> <string name="power_label" msgid="7699720321491287839">"Acender"</string> <string name="power_utterance" msgid="7444296686402104807">"Opcións de acendido"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Aplicacións recentes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-gu/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-gu/strings.xml index adada824ecb7..5e0bec5409c5 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-gu/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-gu/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ઍક્સેસિબિલિટી મેનૂ"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"ઍક્સેસિબિલિટી મેનૂ તમારા ડિવાઇસને નિયંત્રિત કરવા માટે મોટું ઑન-સ્ક્રીન મેનૂ પૂરું પાડે છે. તમે તમારા ડિવાઇસને લૉક કરી શકો છો, વૉલ્યૂમ અને બ્રાઇટનેસ નિયંત્રિત કરી શકો છો, સ્ક્રીનશૉટ લઈ શકો છો અને બીજું ઘણું બધું કરી શકો છો."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ઍક્સેસિબિલિટી સેટિંગ"</string> - <string name="volume_label" msgid="3682221827627150574">"વૉલ્યૂમ"</string> - <string name="volume_utterance" msgid="408291570329066290">"વૉલ્યૂમ નિયંત્રણો"</string> <string name="power_label" msgid="7699720321491287839">"પાવર"</string> <string name="power_utterance" msgid="7444296686402104807">"પાવર વિકલ્પો"</string> <string name="recent_apps_label" msgid="6583276995616385847">"તાજેતરની ઍપ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml index ee558952dd54..a69b3fe98339 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"सुलभता सेटिंग"</string> - <string name="volume_label" msgid="3682221827627150574">"आवाज़"</string> - <string name="volume_utterance" msgid="408291570329066290">"आवाज़ कम या ज़्यादा करने का बटन"</string> <string name="power_label" msgid="7699720321491287839">"पावर बटन"</string> <string name="power_utterance" msgid="7444296686402104807">"पावर बटन के विकल्प"</string> <string name="recent_apps_label" msgid="6583276995616385847">"हाल में इस्तेमाल किए गए ऐप्लिकेशन"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml index 0be6f7536a61..06e85501c808 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Asistent"</string> <string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Postavke pristupačnosti"</string> - <string name="volume_label" msgid="3682221827627150574">"Glasnoća"</string> - <string name="volume_utterance" msgid="408291570329066290">"Kontrole za glasnoću"</string> <string name="power_label" msgid="7699720321491287839">"Napajanje"</string> <string name="power_utterance" msgid="7444296686402104807">"Opcije napajanja"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Nedavne aplikacije"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hu/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hu/strings.xml index 9dce8aefe6f4..f4787928f8f9 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hu/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hu/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Kisegítő lehetőségek menüje"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"A Kisegítő lehetőségek menüje az eszköz vezérlésére szolgáló nagyméretű, képernyőn megjelenő menü. Lezárhatja vele az eszközt, szabályozhatja a hang- és a fényerőt, képernyőképeket készíthet, és egyebekre is használhatja."</string> <string name="assistant_label" msgid="6796392082252272356">"Segéd"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Segéd"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Kisegítő lehetőségek beállításai"</string> - <string name="volume_label" msgid="3682221827627150574">"Hangerő"</string> - <string name="volume_utterance" msgid="408291570329066290">"Hangerő-szabályozó"</string> <string name="power_label" msgid="7699720321491287839">"Bekapcsológomb"</string> <string name="power_utterance" msgid="7444296686402104807">"Bekapcsológomb beállításai"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Legutóbbi alkalmazások"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml index 52d5d0e38799..0a1c8225ae84 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Հատուկ գործառույթների ընտրացանկ"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Հատուկ գործառույթների մեծ ընտրացանկը նախատեսված է ձեր սարքը կառավարելու համար։ Դուք կարող եք կողպել ձեր հեռախոսը, կարգավորել պայծառությունը և ձայնի ուժգնությունը, սքրինշոթներ անել և այլն։"</string> <string name="assistant_label" msgid="6796392082252272356">"Օգնական"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Օգնական"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Հատուկ գործառույթների կարգավորումներ"</string> - <string name="volume_label" msgid="3682221827627150574">"Ձայն"</string> - <string name="volume_utterance" msgid="408291570329066290">"Ձայնի ուժգնության կառավարներ"</string> <string name="power_label" msgid="7699720321491287839">"Սնուցման կոճակ"</string> <string name="power_utterance" msgid="7444296686402104807">"Սնուցման կոճակի ընտրանքներ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Վերջին օգտագործած հավելվածները"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-in/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-in/strings.xml index d58cf89e4a66..efb0999af852 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-in/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-in/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu Aksesibilitas"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Menu Aksesibilitas menyediakan menu di layar dengan ukuran besar untuk mengontrol perangkat Anda. Anda dapat mengunci perangkat, mengontrol volume dan kecerahan, mengambil screenshot, dan banyak lagi."</string> <string name="assistant_label" msgid="6796392082252272356">"Asisten"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asisten"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Setelan Aksesibilitas"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Kontrol volume"</string> <string name="power_label" msgid="7699720321491287839">"Power"</string> <string name="power_utterance" msgid="7444296686402104807">"Opsi power"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Aplikasi terbaru"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-is/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-is/strings.xml index 2a803c16d91c..71047ed3e42f 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-is/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-is/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Aðgengisvalmynd"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Aðgengisvalmyndin er stór valmynd sem birtist á skjánum sem má nota til að stjórna tækinu. Þú getur læst tækinu, stjórnað hljóðstyrk og birtustigi, tekið skjámyndir og fleira."</string> <string name="assistant_label" msgid="6796392082252272356">"Hjálpari"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Hjálpari"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Aðgengisstillingar"</string> - <string name="volume_label" msgid="3682221827627150574">"Hljóðstyrkur"</string> - <string name="volume_utterance" msgid="408291570329066290">"Stýringar hljóðstyrks"</string> <string name="power_label" msgid="7699720321491287839">"Orka"</string> <string name="power_utterance" msgid="7444296686402104807">"Orkuvalkostir"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Nýleg forrit"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-it/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-it/strings.xml index cef36771f1d7..747472174a93 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-it/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-it/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistente"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistente"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Impostazioni di accessibilità"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controlli del volume"</string> <string name="power_label" msgid="7699720321491287839">"Accensione"</string> <string name="power_utterance" msgid="7444296686402104807">"Opzioni di accensione"</string> <string name="recent_apps_label" msgid="6583276995616385847">"App recenti"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml index 6335e969e541..7072b34a9180 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"תפריט נגישות"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"תפריט הנגישות הוא תפריט גדול שמופיע במסך ומאפשר לשלוט במכשיר. אפשר לנעול את המכשיר, לשלוט בעוצמת הקול ובבהירות, לצלם צילומי מסך ועוד."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"הגדרות נגישות"</string> - <string name="volume_label" msgid="3682221827627150574">"עוצמת הקול"</string> - <string name="volume_utterance" msgid="408291570329066290">"שליטה בעוצמת הקול"</string> <string name="power_label" msgid="7699720321491287839">"הפעלה"</string> <string name="power_utterance" msgid="7444296686402104807">"אפשרויות הפעלה"</string> <string name="recent_apps_label" msgid="6583276995616385847">"אפליקציות אחרונות"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ja/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ja/strings.xml index d5ef005503a5..75fd81542183 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ja/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ja/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"アシスタント"</string> <string name="assistant_utterance" msgid="65509599221141377">"アシスタント"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ユーザー補助機能の設定"</string> - <string name="volume_label" msgid="3682221827627150574">"音量"</string> - <string name="volume_utterance" msgid="408291570329066290">"音量を調節"</string> <string name="power_label" msgid="7699720321491287839">"電源"</string> <string name="power_utterance" msgid="7444296686402104807">"電源オプション"</string> <string name="recent_apps_label" msgid="6583276995616385847">"最近使ったアプリ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ka/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ka/strings.xml index 3ba5adc4f88b..62ae27b44c33 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ka/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ka/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"ასისტენტი"</string> <string name="assistant_utterance" msgid="65509599221141377">"ასისტენტი"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"მარტივი წვდომის პარამეტრები"</string> - <string name="volume_label" msgid="3682221827627150574">"ხმა"</string> - <string name="volume_utterance" msgid="408291570329066290">"ხმის მართვის საშუალებები"</string> <string name="power_label" msgid="7699720321491287839">"ელკვება"</string> <string name="power_utterance" msgid="7444296686402104807">"ელკვების ვარიანტები"</string> <string name="recent_apps_label" msgid="6583276995616385847">"ბოლოდროინდელი აპები"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml index b7fbaa89eb9a..79ab05a2e484 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Арнайы мүмкіндіктер мәзірі"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Арнайы мүмкіндіктер мәзірінде құрылғыны басқаруға арналған үлкейтілген экран мәзірі бар. Ол арқылы құрылғыны құлыптай, дыбыс деңгейі мен түс ашықтығын басқара, скриншот түсіре және т.б. әрекеттерді орындай аласыз."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Арнайы мүмкіндіктер параметрлері"</string> - <string name="volume_label" msgid="3682221827627150574">"Дыбыс деңгейі"</string> - <string name="volume_utterance" msgid="408291570329066290">"Дыбыс деңгейін басқару элементтері"</string> <string name="power_label" msgid="7699720321491287839">"Қуат түймесі"</string> <string name="power_utterance" msgid="7444296686402104807">"Қуат түймесінің опциялары"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Соңғы пайдаланылған қолданбалар"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-km/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-km/strings.xml index 6bd12748d560..e091dd99a76d 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-km/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-km/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ម៉ឺនុយភាពងាយស្រួល"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"ម៉ឺនុយភាពងាយស្រួលផ្ដល់ម៉ឺនុយធំនៅលើអេក្រង់ ដើម្បីគ្រប់គ្រងឧបករណ៍របស់អ្នក។ អ្នកអាចចាក់សោឧបករណ៍របស់អ្នក គ្រប់គ្រងកម្រិតសំឡេងនិងពន្លឺ ថតរូបអេក្រង់ និងអ្វីៗច្រើនទៀត។"</string> <string name="assistant_label" msgid="6796392082252272356">"ជំនួយការ"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Google Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ការកំណត់ភាពងាយស្រួល"</string> - <string name="volume_label" msgid="3682221827627150574">"កម្រិតសំឡេង"</string> - <string name="volume_utterance" msgid="408291570329066290">"ការគ្រប់គ្រងកម្រិតសំឡេង"</string> <string name="power_label" msgid="7699720321491287839">"ថាមពល"</string> <string name="power_utterance" msgid="7444296686402104807">"ជម្រើសថាមពល"</string> <string name="recent_apps_label" msgid="6583276995616385847">"កម្មវិធីថ្មីៗ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml index 627cfc135a7e..40b1f351f6fa 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml @@ -1,14 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="accessibility_menu_service_name" msgid="730136711554740131">"ಪ್ರವೇಶಿಸುವಿಕೆ ಮೆನು"</string> - <string name="accessibility_menu_intro" msgid="3164193281544042394">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ನಿಯಂತ್ರಿಸುವುದಕ್ಕಾಗಿ ಪ್ರವೇಶಿಸುವಿಕೆ ಮೆನು ದೊಡ್ಡ ಸ್ಕ್ರೀನ್ ಮೆನುವನ್ನು ಒದಗಿಸುತ್ತದೆ. ನೀವು ನಿಮ್ಮ ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಬಹುದು, ವಾಲ್ಯೂಮ್ ಮತ್ತು ಪ್ರಖರತೆಯನ್ನು ನಿಯಂತ್ರಿಸಬಹುದು, ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು ಮತ್ತು ಇನ್ನೂ ಹೆಚ್ಚಿನವನ್ನು ಮಾಡಬಹುದು."</string> + <string name="accessibility_menu_service_name" msgid="730136711554740131">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಮೆನು"</string> + <string name="accessibility_menu_intro" msgid="3164193281544042394">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ನಿಯಂತ್ರಿಸುವುದಕ್ಕಾಗಿ ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಮೆನು ದೊಡ್ಡ ಸ್ಕ್ರೀನ್ ಮೆನುವನ್ನು ಒದಗಿಸುತ್ತದೆ. ನೀವು ನಿಮ್ಮ ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಬಹುದು, ವಾಲ್ಯೂಮ್ ಮತ್ತು ಪ್ರಖರತೆಯನ್ನು ನಿಯಂತ್ರಿಸಬಹುದು, ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು ಮತ್ತು ಇನ್ನೂ ಹೆಚ್ಚಿನವನ್ನು ಮಾಡಬಹುದು."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> - <string name="a11y_settings_label" msgid="3977714687248445050">"ಪ್ರವೇಶಿಸುವಿಕೆ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> - <string name="volume_label" msgid="3682221827627150574">"ಧ್ವನಿಯ ಶಕ್ತಿ"</string> - <string name="volume_utterance" msgid="408291570329066290">"ಧ್ವನಿಯ ಶಕ್ತಿಯ ನಿಯಂತ್ರಕಗಳು"</string> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> + <string name="a11y_settings_label" msgid="3977714687248445050">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="power_label" msgid="7699720321491287839">"ಪವರ್ ಬಟನ್"</string> <string name="power_utterance" msgid="7444296686402104807">"ಪವರ್ ಆಯ್ಕೆಗಳು"</string> <string name="recent_apps_label" msgid="6583276995616385847">"ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string> @@ -23,11 +20,11 @@ <string name="brightness_down_label" msgid="7115662941913272072">"ಪ್ರಖರತೆ ಕಡಿಮೆ ಮಾಡಿ"</string> <string name="previous_button_content_description" msgid="840869171117765966">"ಹಿಂದಿನ ಸ್ಕ್ರೀನ್ಗೆ ಹೋಗಿ"</string> <string name="next_button_content_description" msgid="6810058269847364406">"ಮುಂದಿನ ಸ್ಕ್ರೀನ್ಗೆ ಹೋಗಿ"</string> - <string name="accessibility_menu_description" msgid="4458354794093858297">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಲು ಪ್ರವೇಶಿಸುವಿಕೆ ಮೆನು ದೊಡ್ಡ ಸ್ಕ್ರೀನ್ ಮೆನುವನ್ನು ಒದಗಿಸುತ್ತದೆ. ನೀವು ನಿಮ್ಮ ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಬಹುದು, ವಾಲ್ಯೂಮ್ ಮತ್ತು ಪ್ರಖರತೆಯನ್ನು ನಿಯಂತ್ರಿಸಬಹುದು, ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು ಮತ್ತು ಇನ್ನೂ ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಬಹುದು."</string> + <string name="accessibility_menu_description" msgid="4458354794093858297">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಲು ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಮೆನು ದೊಡ್ಡ ಸ್ಕ್ರೀನ್ ಮೆನುವನ್ನು ಒದಗಿಸುತ್ತದೆ. ನೀವು ನಿಮ್ಮ ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಬಹುದು, ವಾಲ್ಯೂಮ್ ಮತ್ತು ಪ್ರಖರತೆಯನ್ನು ನಿಯಂತ್ರಿಸಬಹುದು, ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು ಮತ್ತು ಇನ್ನೂ ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಬಹುದು."</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"ದೊಡ್ಡ ಮೆನುವಿನ ಮೂಲಕ ಸಾಧನವನ್ನು ನಿಯಂತ್ರಿಸಿ"</string> - <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"ಪ್ರವೇಶಿಸುವಿಕೆ ಮೆನು ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> + <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಮೆನು ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"ದೊಡ್ಡ ಬಟನ್ಗಳು"</string> - <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"ಪ್ರವೇಶಿಸುವಿಕೆ ಮೆನು ಬಟನ್ಗಳ ಗಾತ್ರವನ್ನು ಹೆಚ್ಚಿಸಿ"</string> + <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಮೆನು ಬಟನ್ಗಳ ಗಾತ್ರವನ್ನು ಹೆಚ್ಚಿಸಿ"</string> <string name="pref_help_title" msgid="6871558837025010641">"ಸಹಾಯ"</string> <string name="brightness_percentage_label" msgid="7391554573977867369">"ಪ್ರಕಾಶಮಾನ <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string> <string name="music_volume_percentage_label" msgid="398635599662604706">"ಸಂಗೀತ ವಾಲ್ಯೂಮ್ <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ko/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ko/strings.xml index f2495f01b25c..b06e43295e14 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ko/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ko/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"접근성 메뉴"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"접근성 메뉴를 사용하면 화면에 크게 표시되는 메뉴로 기기를 제어할 수 있습니다. 기기 잠금, 볼륨 및 밝기 조절, 스크린샷 찍기 등의 작업이 지원됩니다."</string> <string name="assistant_label" msgid="6796392082252272356">"어시스턴트"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"어시스턴트"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"접근성 설정"</string> - <string name="volume_label" msgid="3682221827627150574">"볼륨"</string> - <string name="volume_utterance" msgid="408291570329066290">"볼륨 조정"</string> <string name="power_label" msgid="7699720321491287839">"전원"</string> <string name="power_utterance" msgid="7444296686402104807">"전원 옵션"</string> <string name="recent_apps_label" msgid="6583276995616385847">"최근 앱"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml index c376cf46280e..f6711d35ab1f 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Атайын мүмкүнчүлүктөр менюсу"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Атайын мүмкүнчүлүктөр менюсу аркылуу түзмөгүңүздү кулпулап, үнүн катуулатып/акырындатып, экрандын жарык деңгээлин тууралап, скриншот тартып жана башка нерселерди жасай аласыз."</string> <string name="assistant_label" msgid="6796392082252272356">"Жардамчы"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Жардамчы"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Атайын мүмкүнчүлүктөрдүн параметрлери"</string> - <string name="volume_label" msgid="3682221827627150574">"Үндүн катуулугу"</string> - <string name="volume_utterance" msgid="408291570329066290">"Үндү башкаруу элементтери"</string> <string name="power_label" msgid="7699720321491287839">"Кубат"</string> <string name="power_utterance" msgid="7444296686402104807">"Кубат параметрлери"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Акыркы колдонмолор"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-lo/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-lo/strings.xml index 85891a96ec60..4032565cfc38 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-lo/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-lo/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ເມນູການຊ່ວຍເຂົ້າເຖິງ"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"ເມນູການຊ່ວຍເຂົ້າເຖິງຈະສະໜອງເມນູຢູ່ໜ້າຈໍຂະໜາດໃຫຍ່ເພື່ອຄວບຄຸມອຸປະກອນຂອງທ່ານ. ທ່ານສາມາດລັອກອຸປະກອນຂອງທ່ານ, ຄວບຄຸມລະດັບສຽງ ແລະ ຄວາມສະຫວ່າງ, ຖ່າຍຮູບໜ້າຈໍ ແລະ ອື່ນໆໄດ້."</string> <string name="assistant_label" msgid="6796392082252272356">"ຜູ້ຊ່ວຍ"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"ຜູ້ຊ່ວຍ"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ການຕັ້ງຄ່າການຊ່ວຍເຂົ້າເຖິງ"</string> - <string name="volume_label" msgid="3682221827627150574">"ລະດັບສຽງ"</string> - <string name="volume_utterance" msgid="408291570329066290">"ຕົວຄວບຄຸມລະດັບສຽງ"</string> <string name="power_label" msgid="7699720321491287839">"ພະລັງງານ"</string> <string name="power_utterance" msgid="7444296686402104807">"ຕົວເລືອກພະລັງງານ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"ແອັບຫຼ້າສຸດ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-lt/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-lt/strings.xml index b4d804c5bab4..11d1ffa1ebd2 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-lt/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-lt/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Padėjėjas"</string> <string name="assistant_utterance" msgid="65509599221141377">"Padėjėjas"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Pritaikymo neįgaliesiems nustatymai"</string> - <string name="volume_label" msgid="3682221827627150574">"Garsumas"</string> - <string name="volume_utterance" msgid="408291570329066290">"Garsumo valdikliai"</string> <string name="power_label" msgid="7699720321491287839">"Maitinimas"</string> <string name="power_utterance" msgid="7444296686402104807">"Maitinimo parinktys"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Naujausios programos"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-lv/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-lv/strings.xml index a40b52598e33..4a0c9e611412 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-lv/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-lv/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Pieejamības izvēlne"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Pieejamības izvēlne ir liela ekrāna izvēlne, ar ko varat kontrolēt ierīci. Varat bloķēt ierīci, kontrolēt skaļumu un spilgtumu, veidot ekrānuzņēmumus un paveikt daudz ko citu."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistents"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistents"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Pieejamības iestatījumi"</string> - <string name="volume_label" msgid="3682221827627150574">"Skaļums"</string> - <string name="volume_utterance" msgid="408291570329066290">"Skaļuma vadīklas"</string> <string name="power_label" msgid="7699720321491287839">"Barošana"</string> <string name="power_utterance" msgid="7444296686402104807">"Barošanas opcijas"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Pēdējās izmantotās lietotnes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-mk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-mk/strings.xml index 4a710cc161f8..6ed7dfc8c559 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-mk/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-mk/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Мени за пристапност"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"„Менито за пристапност“ ви овозможува да го контролирате уредот преку големо мени на екранот. Може да го заклучите уредот, да ги контролирате јачината на звукот и осветленоста, да правите слики од екранот и друго."</string> <string name="assistant_label" msgid="6796392082252272356">"Помошник"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Помошник"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Пристапност"</string> - <string name="volume_label" msgid="3682221827627150574">"Јачина на звук"</string> - <string name="volume_utterance" msgid="408291570329066290">"Контроли за јачина на звук"</string> <string name="power_label" msgid="7699720321491287839">"Напојување"</string> <string name="power_utterance" msgid="7444296686402104807">"Опции за напојување"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Неодамнешни апликации"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ml/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ml/strings.xml index 38471e12b70a..00e0a0f51c37 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ml/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ml/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ഉപയോഗസഹായി മെനു"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"നിങ്ങളുടെ ഉപകരണം നിയന്ത്രിക്കുന്നതിന്, ഉപയോഗസഹായി മെനു വലിയൊരു ഓൺ-സ്ക്രീൻ മെനു നൽകുന്നു. ഉപകരണം ലോക്ക് ചെയ്യാനും ശബ്ദവും തെളിച്ചവും നിയന്ത്രിക്കാനും സ്ക്രീൻ ഷോട്ടുകൾ എടുക്കാനും മറ്റും നിങ്ങൾക്ക് കഴിയും."</string> <string name="assistant_label" msgid="6796392082252272356">"അസിസ്റ്റന്റ്"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"പ്രവേശനക്ഷമത ക്രമീകരണം"</string> - <string name="volume_label" msgid="3682221827627150574">"വോളിയം"</string> - <string name="volume_utterance" msgid="408291570329066290">"വോളിയം നിയന്ത്രണങ്ങൾ"</string> <string name="power_label" msgid="7699720321491287839">"പവർ"</string> <string name="power_utterance" msgid="7444296686402104807">"പവർ ഓപ്ഷനുകൾ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"സമീപകാല ആപ്പുകൾ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-mn/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-mn/strings.xml index 7c54d556e244..b3575b1cd73e 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-mn/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-mn/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Хандалтын цэс"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Хандалтын цэс нь танд төхөөрөмжөө том дэлгэцийн цэсээр хянах боломжийг олгоно. Та төхөөрөмжөө түгжих, дууны түвшин болон гэрэлтүүлгийг хянах, дэлгэцийн агшин авах болон бусад үйлдлийг хийж болно."</string> <string name="assistant_label" msgid="6796392082252272356">"Туслах"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Туслах"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Хүртээмжийн тохиргоо"</string> - <string name="volume_label" msgid="3682221827627150574">"Түвшин"</string> - <string name="volume_utterance" msgid="408291570329066290">"Түвшний хяналт"</string> <string name="power_label" msgid="7699720321491287839">"Асаах/унтраах"</string> <string name="power_utterance" msgid="7444296686402104807">"Асаах/унтраах сонголт"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Саяхны апп"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-mr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-mr/strings.xml index 4497e9cae17d..cc1193ed6b22 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-mr/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-mr/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"असिस्टंट"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"अॅक्सेसिबिलिटी सेटिंग्ज"</string> - <string name="volume_label" msgid="3682221827627150574">"व्हॉल्यूम"</string> - <string name="volume_utterance" msgid="408291570329066290">"व्हॉल्यूम नियंत्रणे"</string> <string name="power_label" msgid="7699720321491287839">"पॉवर"</string> <string name="power_utterance" msgid="7444296686402104807">"पॉवर पर्याय"</string> <string name="recent_apps_label" msgid="6583276995616385847">"अलीकडील अॅप्स"</string> @@ -19,7 +17,7 @@ <string name="volume_up_label" msgid="8592766918780362870">"व्हॉल्यूम वाढवा"</string> <string name="volume_down_label" msgid="8574981863656447346">"व्हॉल्यूम कमी करा"</string> <string name="brightness_up_label" msgid="8010753822854544846">"ब्राइटनेस वाढवा"</string> - <string name="brightness_down_label" msgid="7115662941913272072">"कमी ब्राइटनेस"</string> + <string name="brightness_down_label" msgid="7115662941913272072">"ब्राइटनेस कमी करा"</string> <string name="previous_button_content_description" msgid="840869171117765966">"मागील स्क्रीनवर जा"</string> <string name="next_button_content_description" msgid="6810058269847364406">"पुढील स्क्रीनवर जा"</string> <string name="accessibility_menu_description" msgid="4458354794093858297">"तुमचे डिव्हाइस नियंत्रित करण्यासाठी अॅक्सेसिबिलिटी मेनू मोठा स्क्रीनवरील मेनू पुरवतो. तुम्ही तुमचे डिव्हाइस लॉक करणे, व्हॉल्यूम आणि ब्राइटनेस नियंत्रित करणे, स्क्रीनशॉट घेणे आणि आणखी बरेच काही करू शकता."</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml index 64a31513c81e..75964c5b3db1 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Tetapan Kebolehaksesan"</string> - <string name="volume_label" msgid="3682221827627150574">"Kelantangan"</string> - <string name="volume_utterance" msgid="408291570329066290">"Kawalan kelantangan"</string> <string name="power_label" msgid="7699720321491287839">"Kuasa"</string> <string name="power_utterance" msgid="7444296686402104807">"Pilihan kuasa"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Apl terbaharu"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml index daeb106a91be..dacd68ad409d 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml @@ -5,9 +5,7 @@ <string name="accessibility_menu_intro" msgid="3164193281544042394">"‘အများသုံးနိုင်မှု မီနူး’ တွင် သင့်စက်ပစ္စည်းကို စီမံရန် ကြီးမားသည့်ဖန်သားပြင်မီနူး ပါဝင်သည်။ စက်ပစ္စည်းလော့ခ်ချခြင်း၊ အသံအတိုးအကျယ်နှင့် အလင်းအမှောင် ထိန်းချုပ်ခြင်း၊ ဖန်သားပြင်ဓာတ်ပုံရိုက်ခြင်း စသည်တို့ ပြုလုပ်နိုင်သည်။"</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> - <string name="a11y_settings_label" msgid="3977714687248445050">"အများသုံးစွဲနိုင်မှု ဆက်တင်များ"</string> - <string name="volume_label" msgid="3682221827627150574">"အသံအတိုးအကျယ်"</string> - <string name="volume_utterance" msgid="408291570329066290">"အသံအတိုးအကျယ် ခလုတ်များ"</string> + <string name="a11y_settings_label" msgid="3977714687248445050">"အများသုံးနိုင်မှု ဆက်တင်များ"</string> <string name="power_label" msgid="7699720321491287839">"ပါဝါခလုတ်"</string> <string name="power_utterance" msgid="7444296686402104807">"ပါဝါ ရွေးစရာများ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"လတ်တလောသုံး အက်ပ်များ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml index ab4686aef5bc..33e726bc8314 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Tilgjengelighetsmeny"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Med Tilgjengelighet-menyen får du en stor meny på skjermen for å kontrollere enheten. Du kan låse enheten, kontrollere volum og lysstyrke, ta skjermdumper med mer."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Tilgjengelighetsinnstillinger"</string> - <string name="volume_label" msgid="3682221827627150574">"Volum"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volumkontroller"</string> <string name="power_label" msgid="7699720321491287839">"Av/på"</string> <string name="power_utterance" msgid="7444296686402104807">"Av/på-alternativer"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Nylige apper"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml index 82b6285871a6..e77bb33acd12 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"एक्सेसिबिलिटी मेनु"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"तपाईं आफ्नो डिभाइस नियन्त्रण गर्न एक्सेसिबिलिटी मेनुमा गई ठुलो अन स्क्रिन मेनु खोल्न सक्नुहुन्छ। तपाईं आफ्नो डिभाइस लक गर्न, भोल्युम र चमक नियन्त्रण गर्न, स्क्रिनसटहरू लिन र थप कार्यहरू गर्न सक्नुहुन्छ।"</string> <string name="assistant_label" msgid="6796392082252272356">"सहायक"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"सहायक"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"पहुँचसम्बन्धी सेटिङहरू"</string> - <string name="volume_label" msgid="3682221827627150574">"भोल्युम"</string> - <string name="volume_utterance" msgid="408291570329066290">"भोल्युमका नियन्त्रणहरू"</string> <string name="power_label" msgid="7699720321491287839">"पावर बटन"</string> <string name="power_utterance" msgid="7444296686402104807">"पावर बटनका विकल्पहरू"</string> <string name="recent_apps_label" msgid="6583276995616385847">"हालका एपहरू"</string> @@ -25,9 +22,9 @@ <string name="next_button_content_description" msgid="6810058269847364406">"अर्को स्क्रिनमा जानुहोस्"</string> <string name="accessibility_menu_description" msgid="4458354794093858297">"तपाईं आफ्नो डिभाइस नियन्त्रण गर्न एक्सेसिबिलिटी मेनुमा गई ठुलो अन स्क्रिन मेनु खोल्न सक्नुहुन्छ। तपाईं आफ्नो डिभाइस लक गर्न, भोल्युम र चमक नियन्त्रण गर्न, स्क्रिनसटहरू लिन र थप कार्यहरू गर्न सक्नुहुन्छ।"</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"ठुलो मेनुको सहायताले डिभाइस नियन्त्रण गर्नुहोस्"</string> - <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"पहुँचसम्बन्धी मेनुका सेटिङहरू"</string> + <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"एक्सेसिबिलिटी मेनुसम्बन्धी सेटिङ"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"ठूला बटनहरू"</string> - <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Accessibility मेनुका बटनहरूको आकार बढाउनुहोस्"</string> + <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"एक्सेसिबिलिटी मेनुका बटनहरूको आकार बढाउनुहोस्"</string> <string name="pref_help_title" msgid="6871558837025010641">"मद्दत"</string> <string name="brightness_percentage_label" msgid="7391554573977867369">"चमक <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string> <string name="music_volume_percentage_label" msgid="398635599662604706">"सङ्गीतको भोल्युम <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml index 1ddf6cfb8a20..3e42ffce88d3 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Toegankelijkheidsmenu"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Het toegankelijkheidsmenu is een groot menu op het scherm waarmee je je apparaat kunt bedienen. Je kunt onder meer je apparaat vergrendelen, het volume en de helderheid beheren en screenshots maken."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Instellingen voor toegankelijkheid"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volumebediening"</string> <string name="power_label" msgid="7699720321491287839">"Voeding"</string> <string name="power_utterance" msgid="7444296686402104807">"Voedingsopties"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Recente apps"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml index dd46ae471b14..9b42865693c0 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ଆକ୍ସେସିବିଲିଟୀ ମେନୁ"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"ଆପଣଙ୍କ ଡିଭାଇସକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ ଆକ୍ସେସିବିଲିଟୀ ମେନୁ ଏକ ବଡ଼ ଅନ-ସ୍କ୍ରିନ ମେନୁ ପ୍ରଦାନ କରେ। ଆପଣ ଆପଣଙ୍କ ଡିଭାଇସକୁ ଲକ କରିପାରିବେ, ଭଲ୍ୟୁମ ଓ ଉଜ୍ଜ୍ୱଳତାକୁ ନିୟନ୍ତ୍ରଣ କରିପାରିବେ, ସ୍କ୍ରିନସଟ ନେଇପାରିବେ ଏବଂ ଆହୁରି ଅନେକ କିଛି କରିପାରିବେ।"</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ଆକ୍ସେସିବିଲିଟୀ ସେଟିଂସ"</string> - <string name="volume_label" msgid="3682221827627150574">"ଭଲ୍ୟୁମ୍"</string> - <string name="volume_utterance" msgid="408291570329066290">"ଭଲ୍ୟୁମ୍ କଣ୍ଟ୍ରୋଲ୍"</string> <string name="power_label" msgid="7699720321491287839">"ପାୱର୍"</string> <string name="power_utterance" msgid="7444296686402104807">"ପାୱର୍ ବିକଳ୍ପ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"ବର୍ତ୍ତମାନର ଆପ୍"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml index 4ff57c01bd0d..31fab247336b 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ਪਹੁੰਚਯੋਗਤਾ ਮੀਨੂ"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਪਹੁੰਚਯੋਗਤਾ ਮੀਨੂ ਇੱਕ ਵੱਡਾ ਆਨ-ਸਕ੍ਰੀਨ ਮੀਨੂ ਮੁਹੱਈਆ ਕਰਦਾ ਹੈ। ਤੁਸੀਂ ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਲਾਕ ਕਰ ਸਕਦੇ ਹੋ, ਅਵਾਜ਼ ਅਤੇ ਚਮਕ ਨੂੰ ਕੰਟਰੋਲ ਕਰ ਸਕਦੇ ਹੋ, ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈ ਸਕਦੇ ਹੋ ਅਤੇ ਹੋਰ ਵੀ ਬਹੁਤ ਕੁਝ।"</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ਪਹੁੰਚਯੋਗਤਾ ਸੈਟਿੰਗਾਂ"</string> - <string name="volume_label" msgid="3682221827627150574">"ਅਵਾਜ਼"</string> - <string name="volume_utterance" msgid="408291570329066290">"ਵੌਲਿਊਮ ਕੰਟਰੋਲ"</string> <string name="power_label" msgid="7699720321491287839">"ਪਾਵਰ"</string> <string name="power_utterance" msgid="7444296686402104807">"ਪਾਵਰ ਵਿਕਲਪ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"ਹਾਲੀਆ ਐਪਾਂ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pl/strings.xml index 829ab47fcde0..69a08347ce85 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pl/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pl/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu ułatwień dostępu"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Menu ułatwień dostępu to duże menu ekranowe, które umożliwia obsługę urządzenia. Możesz zablokować urządzenie, zwiększyć lub zmniejszyć głośność oraz jasność, zrobić zrzut ekranu i wykonać inne działania."</string> <string name="assistant_label" msgid="6796392082252272356">"Asystent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asystent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Ustawienia ułatwień dostępu"</string> - <string name="volume_label" msgid="3682221827627150574">"Głośność"</string> - <string name="volume_utterance" msgid="408291570329066290">"Przyciski sterowania głośnością"</string> <string name="power_label" msgid="7699720321491287839">"Zasilanie"</string> <string name="power_utterance" msgid="7444296686402104807">"Opcje przycisku zasilania"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Ostatnie aplikacje"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml index 37f0980bbc55..caf15635cc53 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistente"</string> <string name="assistant_utterance" msgid="65509599221141377">"Google Assistente"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Configurações de acessibilidade"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controles de volume"</string> <string name="power_label" msgid="7699720321491287839">"Liga/desliga"</string> <string name="power_utterance" msgid="7444296686402104807">"Opções do botão liga/desliga"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Apps recentes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml index da61be6e5721..d272c21dca7a 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistente"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistente"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Definições de acessibilidade"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controlos do volume"</string> <string name="power_label" msgid="7699720321491287839">"Ligar/desligar"</string> <string name="power_utterance" msgid="7444296686402104807">"Opções para ligar/desligar"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Apps recentes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml index 37f0980bbc55..caf15635cc53 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistente"</string> <string name="assistant_utterance" msgid="65509599221141377">"Google Assistente"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Configurações de acessibilidade"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Controles de volume"</string> <string name="power_label" msgid="7699720321491287839">"Liga/desliga"</string> <string name="power_utterance" msgid="7444296686402104807">"Opções do botão liga/desliga"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Apps recentes"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ro/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ro/strings.xml index 77b4318e8fa0..6edbb77e37eb 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ro/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ro/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Meniul Accesibilitate"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Meniul Accesibilitate este un meniu mare afișat pe ecran, cu ajutorul căruia îți controlezi dispozitivul. Poți să blochezi dispozitivul, să ajustezi volumul și luminozitatea, să faci capturi de ecran și multe altele."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Setări de accesibilitate"</string> - <string name="volume_label" msgid="3682221827627150574">"Volum"</string> - <string name="volume_utterance" msgid="408291570329066290">"Comenzi pentru volum"</string> <string name="power_label" msgid="7699720321491287839">"Alimentare"</string> <string name="power_utterance" msgid="7444296686402104807">"Opțiuni pentru alimentare"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Aplicații recente"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ru/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ru/strings.xml index 1e9ec497a697..d99d57b87832 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ru/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ru/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Меню спец. возможностей"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"С помощью большого экранного меню специальных возможностей можно блокировать устройство, регулировать громкость звука и яркость экрана, делать скриншоты и выполнять другие действия."</string> <string name="assistant_label" msgid="6796392082252272356">"Ассистент"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Ассистент"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Настройки специальных возможностей"</string> - <string name="volume_label" msgid="3682221827627150574">"Громкость"</string> - <string name="volume_utterance" msgid="408291570329066290">"Кнопки регулировки громкости"</string> <string name="power_label" msgid="7699720321491287839">"Кнопка питания"</string> <string name="power_utterance" msgid="7444296686402104807">"Настройки кнопки питания"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Недавние приложения"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-si/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-si/strings.xml index ecd4c16c09d5..10573df25742 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-si/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-si/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ප්රවේශ්යතා මෙනුව"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"ප්රවේශ්යතා මෙනුව ඔබගේ උපාංගය පාලනය කිරීම සඳහා විශාල තිරය මත මෙනුවක් සපයයි. ඔබට ඔබගේ උපාංගය අගුලු හැරීමට, හඬ පරිමාව සහ දීප්තිය පාලනය කිරීමට, තිර රූ ගැනීමට සහ තවත් දේ කිරීමට හැකිය."</string> <string name="assistant_label" msgid="6796392082252272356">"සහායක"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"සහායක"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ප්රවේශ්යතා සැකසීම්"</string> - <string name="volume_label" msgid="3682221827627150574">"ශබ්දය"</string> - <string name="volume_utterance" msgid="408291570329066290">"හඬ පරිමා පාලන"</string> <string name="power_label" msgid="7699720321491287839">"බලය"</string> <string name="power_utterance" msgid="7444296686402104807">"බලය විකල්ප"</string> <string name="recent_apps_label" msgid="6583276995616385847">"මෑත යෙදුම්"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml index a8c8a89f3fb8..6b9ac5c26a1e 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Ponuka dostupnosti"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Ponuka dostupnosti spustí na obrazovke telefónu veľkú ponuku, pomocou ktorej môžete ovládať svoje zariadenie. Môžete ho uzamknúť, ovládať hlasitosť a jas, vytvárať snímky obrazovky a mnoho ďalšieho."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Nastavenia dostupnosti"</string> - <string name="volume_label" msgid="3682221827627150574">"Hlasitosť"</string> - <string name="volume_utterance" msgid="408291570329066290">"Ovládanie hlasitosti"</string> <string name="power_label" msgid="7699720321491287839">"Vypínač"</string> <string name="power_utterance" msgid="7444296686402104807">"Možnosti vypínača"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Nedávne aplikácie"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sl/strings.xml index aaa576d0534e..8f63972c3846 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sl/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sl/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Meni s funkcijami za ljudi s posebnimi potrebami"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Meni s funkcijami za ljudi s posebnimi potrebami je velik zaslonski meni za upravljanje naprave. V njem lahko zaklenete napravo, nastavljate glasnost in svetlost, zajamete posnetke zaslona in drugo."</string> <string name="assistant_label" msgid="6796392082252272356">"Pomočnik"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Pomočnik"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Nastavitve funkcij za ljudi s posebnimi potrebami"</string> - <string name="volume_label" msgid="3682221827627150574">"Glasnost"</string> - <string name="volume_utterance" msgid="408291570329066290">"Kontrolniki za glasnost"</string> <string name="power_label" msgid="7699720321491287839">"Vklop"</string> <string name="power_utterance" msgid="7444296686402104807">"Možnosti gumba za vklop"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Nedavne aplikacije"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sq/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sq/strings.xml index 2dfe2e7115f3..d8141dae4d03 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sq/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sq/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menyja e qasshmërisë"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"\"Menyja e qasshmërisë\" ofron një meny të madhe në ekran për të kontrolluar pajisjen tënde. Mund të kyçësh pajisjen, të kontrollosh volumin dhe ndriçimin, të nxjerrësh pamje ekrani dhe të tjera."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistenti"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistenti"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Cilësimet e qasshmërisë"</string> - <string name="volume_label" msgid="3682221827627150574">"Volumi"</string> - <string name="volume_utterance" msgid="408291570329066290">"Kontrollet e volumit"</string> <string name="power_label" msgid="7699720321491287839">"Energjia"</string> <string name="power_utterance" msgid="7444296686402104807">"Opsionet e energjisë"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Aplikacionet e fundit"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sr/strings.xml index 6538c43cad75..d510915560ba 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sr/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sr/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Мени Приступачност"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Мени Приступачност пружа велики мени на екрану за контролу уређаја. Можете да закључате уређај, контролишете јачину звука и осветљеност, правите снимке екрана и друго."</string> <string name="assistant_label" msgid="6796392082252272356">"Помоћник"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Помоћник"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Подешавања приступачности"</string> - <string name="volume_label" msgid="3682221827627150574">"Јачина звука"</string> - <string name="volume_utterance" msgid="408291570329066290">"Контроле јачине звука"</string> <string name="power_label" msgid="7699720321491287839">"Напајање"</string> <string name="power_utterance" msgid="7444296686402104807">"Опције напајања"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Недавне апликације"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sv/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sv/strings.xml index 2e7a49655133..24dbc3e00f6d 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sv/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sv/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Tillgänglighetsmenyn"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Tillgänglighetsmenyn är en stor meny på skärmen som du kan styra enheten med. Du kan låsa enheten, ställa in volym och ljusstyrka, ta skärmbilder och annat."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Tillgänglighetsinställningar"</string> - <string name="volume_label" msgid="3682221827627150574">"Volym"</string> - <string name="volume_utterance" msgid="408291570329066290">"Volymkontroller"</string> <string name="power_label" msgid="7699720321491287839">"Styrka"</string> <string name="power_utterance" msgid="7444296686402104807">"Strömalternativ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Senaste apparna"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sw/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sw/strings.xml index c7a52aede4e8..77432db1439a 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sw/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sw/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menyu ya Ufikivu"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Menyu ya Ufikivu huonyesha menyu pana iliyo kwenye skrini ili udhibiti kifaa chako. Unaweza kufunga kifaa chako, kudhibiti sauti na ung\'avu, kupiga picha ya skrini na zaidi."</string> <string name="assistant_label" msgid="6796392082252272356">"Mratibu"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Programu ya Mratibu"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Mipangilio ya Ufikivu"</string> - <string name="volume_label" msgid="3682221827627150574">"Sauti"</string> - <string name="volume_utterance" msgid="408291570329066290">"Vidhibiti vya sauti"</string> <string name="power_label" msgid="7699720321491287839">"Nishati"</string> <string name="power_utterance" msgid="7444296686402104807">"Chaguo za kuwasha"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Programu za hivi karibuni"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ta/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ta/strings.xml index 0172b5b3669d..b61632dadf14 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ta/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ta/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"அணுகல்தன்மை மெனு"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"அணுகல்தன்மை மெனுவானது உங்கள் சாதனத்தைக் கட்டுப்படுத்துவதற்கு, திரையில் தோன்றும் பெரிய மெனுவை வழங்குகிறது. சாதனத்தைப் பூட்டுதல், ஒலியளவையும் ஒளிர்வையும் மாற்றுதல், ஸ்கிரீன்ஷாட்களை எடுத்தல் போன்ற பலவற்றைச் செய்யலாம்."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"அசிஸ்டண்ட்"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"அணுகல்தன்மை அமைப்புகள்"</string> - <string name="volume_label" msgid="3682221827627150574">"ஒலியளவு"</string> - <string name="volume_utterance" msgid="408291570329066290">"ஒலியளவுக் கட்டுப்பாடுகள்"</string> <string name="power_label" msgid="7699720321491287839">"பவர் பட்டன்"</string> <string name="power_utterance" msgid="7444296686402104807">"பவர் பட்டன் விருப்பங்கள்"</string> <string name="recent_apps_label" msgid="6583276995616385847">"சமீபத்திய ஆப்ஸ்"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-te/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-te/strings.xml index 54b10f1d8387..4633a73b8980 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-te/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-te/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"యాక్సెసిబిలిటీ మెనూ"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"మీ పరికరాన్ని కంట్రోల్ చేయడానికి యాక్సెసిబిలిటీ మెనూ, స్క్రీన్పై పెద్ద మెనూను అందిస్తుంది. మీరు మీ పరికరాన్ని లాక్ చేయవచ్చు, వాల్యూమ్ మరియు ప్రకాశాన్ని కంట్రోల్ చేయవచ్చు, స్క్రీన్షాట్లు తీసుకోవచ్చు, మరిన్ని చేయవచ్చు."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"యాక్సెస్ సామర్థ్య సెట్టింగ్లు"</string> - <string name="volume_label" msgid="3682221827627150574">"వాల్యూమ్"</string> - <string name="volume_utterance" msgid="408291570329066290">"వాల్యూమ్ నియంత్రణలు"</string> <string name="power_label" msgid="7699720321491287839">"పవర్"</string> <string name="power_utterance" msgid="7444296686402104807">"పవర్ ఎంపికలు"</string> <string name="recent_apps_label" msgid="6583276995616385847">"ఇటీవలి యాప్లు"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-th/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-th/strings.xml index 5748b5cb9afa..29581a9475b0 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-th/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-th/strings.xml @@ -6,8 +6,6 @@ <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"การตั้งค่าการช่วยเหลือพิเศษ"</string> - <string name="volume_label" msgid="3682221827627150574">"ระดับเสียง"</string> - <string name="volume_utterance" msgid="408291570329066290">"การควบคุมเสียง"</string> <string name="power_label" msgid="7699720321491287839">"เปิด/ปิด"</string> <string name="power_utterance" msgid="7444296686402104807">"ตัวเลือกสำหรับการเปิด/ปิด"</string> <string name="recent_apps_label" msgid="6583276995616385847">"แอปล่าสุด"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-tl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-tl/strings.xml index ed1269baffd7..4a5833fbd91f 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-tl/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-tl/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu ng Accessibility"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Nagbibigay ang Menu ng Accessibility ng malaking menu sa screen para sa pagkontrol sa iyong device. Magagawa mong i-lock ang iyong device, kontrolin ang volume at liwanag, kumuha ng mga screenshot, at higit pa."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Mga Setting ng Accessibility"</string> - <string name="volume_label" msgid="3682221827627150574">"Volume"</string> - <string name="volume_utterance" msgid="408291570329066290">"Mga kontrol ng volume"</string> <string name="power_label" msgid="7699720321491287839">"Power"</string> <string name="power_utterance" msgid="7444296686402104807">"Mga opsyon sa power"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Mga kamakailang app"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml index 76a6ec7d8eb6..a648e6b60e5f 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-tr/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Erişilebilirlik Menüsü"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Erişilebilirlik menüsü, cihazınızı kontrol etmeniz için geniş bir ekran menüsü sağlar. Cihazınızı kilitleyebilir, ses düzeyini ve parlaklığı kontrol edebilir, ekran görüntüsü alabilir ve daha fazlasını yapabilirsiniz."</string> <string name="assistant_label" msgid="6796392082252272356">"Asistan"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Asistan"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Erişebilirlik Ayarları"</string> - <string name="volume_label" msgid="3682221827627150574">"Ses düzeyi"</string> - <string name="volume_utterance" msgid="408291570329066290">"Ses denetimleri"</string> <string name="power_label" msgid="7699720321491287839">"Güç"</string> <string name="power_utterance" msgid="7444296686402104807">"Güç seçenekleri"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Son uygulamalar"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-uk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-uk/strings.xml index 970ba2183a12..a9d589b672b2 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-uk/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-uk/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Меню спеціальних можливостей"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"За допомогою великого екранного меню спеціальних можливостей можна заблокувати пристрій, змінювати гучність і яскравість, робити знімки екрана та багато іншого."</string> <string name="assistant_label" msgid="6796392082252272356">"Асистент"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Асистент"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Налаштування спеціальніх можливостей"</string> - <string name="volume_label" msgid="3682221827627150574">"Гучність"</string> - <string name="volume_utterance" msgid="408291570329066290">"Регулятори гучності"</string> <string name="power_label" msgid="7699720321491287839">"Живлення"</string> <string name="power_utterance" msgid="7444296686402104807">"Опції живлення"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Нещодавні додатки"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ur/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ur/strings.xml index b1f2f3b67de2..c93286082542 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ur/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ur/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"ایکسیسبیلٹی مینو"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"اپنے آلے کو کنٹرول کرنے کے لیے ایکسیسبیلٹی مینو ایک بڑا آن اسکرین مینو فراہم کرتا ہے۔ آپ اپنا آلہ مقفل، والیوم اور چمک کو کنٹرول، اسکرین شاٹ لینے کے ساتھ اور مزید بہت کچھ کر سکتے ہیں۔"</string> <string name="assistant_label" msgid="6796392082252272356">"اسسٹنٹ"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"اسسٹنٹ"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"ایکسیسبیلٹی ترتیبات"</string> - <string name="volume_label" msgid="3682221827627150574">"والیوم"</string> - <string name="volume_utterance" msgid="408291570329066290">"والیوم کے کنٹرولز"</string> <string name="power_label" msgid="7699720321491287839">"پاور"</string> <string name="power_utterance" msgid="7444296686402104807">"پاور کے اختیارات"</string> <string name="recent_apps_label" msgid="6583276995616385847">"حالیہ ایپس"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-uz/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-uz/strings.xml index 63af1b136a5c..fa251b86ea7c 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-uz/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-uz/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Maxsus imkoniyatlar menyusi"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Maxsus imkoniyatlar menyusi telefoningizni boshqarish uchun katta menyuni taqdim etadi. Bu menyu orqali telefonni qulflash, ovoz balandligi va yorqinlikni boshqarish, skrinshotlar olish kabi amallarni bajarish mumkin."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Maxsus imkoniyatlar sozlamalari"</string> - <string name="volume_label" msgid="3682221827627150574">"Tovush balandligi"</string> - <string name="volume_utterance" msgid="408291570329066290">"Tovush balandligi tugmalari"</string> <string name="power_label" msgid="7699720321491287839">"Quvvat"</string> <string name="power_utterance" msgid="7444296686402104807">"Quvvat parametrlari"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Yaqinda ishlatilgan ilovalar"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-vi/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-vi/strings.xml index e22a9ab2d91c..ee4dd2507f66 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-vi/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-vi/strings.xml @@ -2,13 +2,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="accessibility_menu_service_name" msgid="730136711554740131">"Trình đơn hỗ trợ tiếp cận"</string> - <string name="accessibility_menu_intro" msgid="3164193281544042394">"Menu Hỗ trợ tiếp cận cung cấp một trình đơn lớn trên màn hình dùng để điều khiển thiết bị. Bạn có thể khóa thiết bị, điều chỉnh âm lượng và độ sáng, chụp ảnh màn hình và nhiều chức năng khác."</string> + <string name="accessibility_menu_intro" msgid="3164193281544042394">"Trình đơn hỗ trợ tiếp cận cung cấp một trình đơn lớn trên màn hình dùng để điều khiển thiết bị. Bạn có thể khóa thiết bị, điều chỉnh âm lượng và độ sáng, chụp ảnh màn hình và thực hiện nhiều chức năng khác."</string> <string name="assistant_label" msgid="6796392082252272356">"Trợ lý"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Trợ lý"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Cài đặt hỗ trợ tiếp cận"</string> - <string name="volume_label" msgid="3682221827627150574">"Âm lượng"</string> - <string name="volume_utterance" msgid="408291570329066290">"Điều khiển âm lượng"</string> <string name="power_label" msgid="7699720321491287839">"Nguồn"</string> <string name="power_utterance" msgid="7444296686402104807">"Tùy chọn nút Nguồn"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Ứng dụng gần đây"</string> @@ -23,7 +20,7 @@ <string name="brightness_down_label" msgid="7115662941913272072">"Giảm độ sáng"</string> <string name="previous_button_content_description" msgid="840869171117765966">"Chuyển đến màn hình trước"</string> <string name="next_button_content_description" msgid="6810058269847364406">"Chuyển đến màn hình tiếp theo"</string> - <string name="accessibility_menu_description" msgid="4458354794093858297">"Menu Hỗ trợ tiếp cận cung cấp một trình đơn lớn trên màn hình dùng để điều khiển thiết bị. Bạn có thể khóa thiết bị, điều chỉnh âm lượng và độ sáng, chụp ảnh màn hình và nhiều việc khác."</string> + <string name="accessibility_menu_description" msgid="4458354794093858297">"Trình đơn hỗ trợ tiếp cận cung cấp một trình đơn lớn trên màn hình dùng để điều khiển thiết bị. Bạn có thể khóa thiết bị, điều chỉnh âm lượng và độ sáng, chụp ảnh màn hình và thực hiện nhiều chức năng khác."</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"Điều khiển thiết bị qua trình đơn lớn"</string> <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Cài đặt Trình đơn Hỗ trợ tiếp cận"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Nút lớn"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rCN/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rCN/strings.xml index e34f8d537a06..425c8e56bf81 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rCN/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"无障碍功能菜单"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"无障碍功能菜单可在屏幕上提供一个大号的菜单,供您控制设备,比如锁定设备、控制音量和亮度、截取屏幕快照等。"</string> <string name="assistant_label" msgid="6796392082252272356">"Google 助理"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Google 助理"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"无障碍设置"</string> - <string name="volume_label" msgid="3682221827627150574">"音量"</string> - <string name="volume_utterance" msgid="408291570329066290">"音量控件"</string> <string name="power_label" msgid="7699720321491287839">"电源"</string> <string name="power_utterance" msgid="7444296686402104807">"电源选项"</string> <string name="recent_apps_label" msgid="6583276995616385847">"最近用过的应用"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rHK/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rHK/strings.xml index e08e52f36fa6..08d26b52fa04 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rHK/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"無障礙功能選單"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"「無障礙功能選單」是螢幕上的大型選單,用來控制裝置,方便您鎖定裝置、控制音量和亮度、擷取螢幕畫面及執行其他功能。"</string> <string name="assistant_label" msgid="6796392082252272356">"Google 助理"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Google 助理"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"無障礙功能設定"</string> - <string name="volume_label" msgid="3682221827627150574">"音量"</string> - <string name="volume_utterance" msgid="408291570329066290">"音量控制項"</string> <string name="power_label" msgid="7699720321491287839">"電源"</string> <string name="power_utterance" msgid="7444296686402104807">"電源選項"</string> <string name="recent_apps_label" msgid="6583276995616385847">"最近使用的應用程式"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rTW/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rTW/strings.xml index a6dfe71cfada..65e90b220f11 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zh-rTW/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"無障礙選單"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"無障礙工具選單是螢幕上的大型選單,可用來操控裝置,方便你鎖定裝置、控制音量和亮度、擷取螢幕畫面,以及執行其他功能。"</string> <string name="assistant_label" msgid="6796392082252272356">"Google 助理"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"Google 助理"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"無障礙設定"</string> - <string name="volume_label" msgid="3682221827627150574">"音量"</string> - <string name="volume_utterance" msgid="408291570329066290">"音量控制項"</string> <string name="power_label" msgid="7699720321491287839">"電源"</string> <string name="power_utterance" msgid="7444296686402104807">"電源選項"</string> <string name="recent_apps_label" msgid="6583276995616385847">"最近使用的應用程式"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zu/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zu/strings.xml index bf7095703edb..b6f3ef9bce4a 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-zu/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-zu/strings.xml @@ -4,11 +4,8 @@ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Imenyu yokufinyeleleka"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Imenyu yokufinyelela inikezela ngemenyu enkulu esesikrinini ukuze ulawule idivayisi yakho. Ungakhiya idivayisi yakho, ulawule ivolumu nokukhanya, uthathe izithombe-skrini, nokuningi."</string> <string name="assistant_label" msgid="6796392082252272356">"Umsizi"</string> - <!-- no translation found for assistant_utterance (65509599221141377) --> - <skip /> + <string name="assistant_utterance" msgid="65509599221141377">"I-Assistant"</string> <string name="a11y_settings_label" msgid="3977714687248445050">"Izilungiselelo zokufinyelela"</string> - <string name="volume_label" msgid="3682221827627150574">"Ivolumu"</string> - <string name="volume_utterance" msgid="408291570329066290">"Izilawuli zevolumu"</string> <string name="power_label" msgid="7699720321491287839">"Amandla"</string> <string name="power_utterance" msgid="7444296686402104807">"Izinketho zamandla"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Izinhlelo zokusebenza zakamuva"</string> diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/multishade/ui/composable/Shade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/multishade/ui/composable/Shade.kt index 98ef57f94783..cfcc2fb251fd 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/multishade/ui/composable/Shade.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/multishade/ui/composable/Shade.kt @@ -22,7 +22,6 @@ import androidx.compose.foundation.interaction.DragInteraction import androidx.compose.foundation.interaction.InteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface @@ -41,6 +40,7 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.android.compose.modifiers.height +import com.android.compose.modifiers.padding import com.android.compose.swipeable.FixedThreshold import com.android.compose.swipeable.SwipeableState import com.android.compose.swipeable.ThresholdConfig @@ -48,6 +48,7 @@ import com.android.compose.swipeable.rememberSwipeableState import com.android.compose.swipeable.swipeable import com.android.systemui.multishade.shared.model.ProxiedInputModel import com.android.systemui.multishade.ui.viewmodel.ShadeViewModel +import kotlin.math.min import kotlin.math.roundToInt import kotlinx.coroutines.launch @@ -145,13 +146,31 @@ private fun ShadeContent( modifier: Modifier = Modifier, content: @Composable () -> Unit = {}, ) { + /** + * Returns a function that takes in [Density] and returns the current padding around the shade + * content. + */ + fun padding( + shadeHeightPx: () -> Float, + ): Density.() -> Int { + return { + min( + 12.dp.toPx().roundToInt(), + shadeHeightPx().roundToInt(), + ) + } + } + Surface( shape = RoundedCornerShape(32.dp), modifier = modifier - .padding(12.dp) .fillMaxWidth() .height { shadeHeightPx().roundToInt() } + .padding( + horizontal = padding(shadeHeightPx), + vertical = padding(shadeHeightPx), + ) .graphicsLayer { // Applies the vertical over-stretching of the shade content that may happen if // the user keep dragging down when the shade is already fully-expanded. diff --git a/packages/SystemUI/docs/user-switching.md b/packages/SystemUI/docs/user-switching.md index b9509eb41c3c..01cba426f782 100644 --- a/packages/SystemUI/docs/user-switching.md +++ b/packages/SystemUI/docs/user-switching.md @@ -6,7 +6,7 @@ Multiple users and the ability to switch between them is controlled by Settings ### Quick Settings -In the QS footer, an icon becomes available for users to tap on. The view and its onClick actions are handled by [MultiUserSwitchController][2]. Multiple visual implementations are currently in use; one for phones/foldables ([UserSwitchDialogController][6]) and one for tablets ([UserSwitcherActivity][5]). +In the QS footer, an icon becomes available for users to tap on. The view and its onClick actions are handled by [MultiUserSwitchController][2]. Multiple visual implementations are currently in use; one for phones/foldables ([UserSwitchDialogController][6]) and one for tablets ([UserSwitcherFullscreenDialog][5]). ### Bouncer @@ -29,7 +29,7 @@ All visual implementations should derive their logic and use the adapter specifi ## Visual Components -### [UserSwitcherActivity][5] +### [UserSwitcherFullscreenDialog][5] A fullscreen user switching activity, supporting add guest/user actions if configured. @@ -41,5 +41,5 @@ Renders user switching as a dialog over the current surface, and supports add gu [2]: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserController.java [3]: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java [4]: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java -[5]: /frameworks/base/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +[5]: /frameworks/base/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt [6]: /frameworks/base/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt index db88b593e432..204bac88bc0d 100644 --- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt +++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt @@ -23,6 +23,8 @@ import com.android.internal.graphics.ColorUtils import com.android.internal.graphics.cam.Cam import com.android.internal.graphics.cam.CamUtils import kotlin.math.absoluteValue +import kotlin.math.max +import kotlin.math.min import kotlin.math.roundToInt const val TAG = "ColorScheme" @@ -35,12 +37,12 @@ internal interface Hue { fun get(sourceColor: Cam): Double /** - * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the - * hue fall betweens, and use the hue rotation of the lower hue. + * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the hue + * fall betweens, and use the hue rotation of the lower hue. * * @param sourceHue hue of source color - * @param hueAndRotations list of pairs, where the first item in a pair is a hue, and the - * second item in the pair is a hue rotation that should be applied + * @param hueAndRotations list of pairs, where the first item in a pair is a hue, and the second + * item in the pair is a hue rotation that should be applied */ fun getHueRotation(sourceHue: Float, hueAndRotations: List<Pair<Int, Int>>): Double { val sanitizedSourceHue = (if (sourceHue < 0 || sourceHue >= 360) 0 else sourceHue).toFloat() @@ -48,8 +50,9 @@ internal interface Hue { val thisHue = hueAndRotations[i].first.toFloat() val nextHue = hueAndRotations[i + 1].first.toFloat() if (thisHue <= sanitizedSourceHue && sanitizedSourceHue < nextHue) { - return ColorScheme.wrapDegreesDouble(sanitizedSourceHue.toDouble() + - hueAndRotations[i].second) + return ColorScheme.wrapDegreesDouble( + sanitizedSourceHue.toDouble() + hueAndRotations[i].second + ) } } @@ -78,8 +81,18 @@ internal class HueSubtract(val amountDegrees: Double) : Hue { } internal class HueVibrantSecondary() : Hue { - val hueToRotations = listOf(Pair(0, 18), Pair(41, 15), Pair(61, 10), Pair(101, 12), - Pair(131, 15), Pair(181, 18), Pair(251, 15), Pair(301, 12), Pair(360, 12)) + val hueToRotations = + listOf( + Pair(0, 18), + Pair(41, 15), + Pair(61, 10), + Pair(101, 12), + Pair(131, 15), + Pair(181, 18), + Pair(251, 15), + Pair(301, 12), + Pair(360, 12) + ) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) @@ -87,8 +100,18 @@ internal class HueVibrantSecondary() : Hue { } internal class HueVibrantTertiary() : Hue { - val hueToRotations = listOf(Pair(0, 35), Pair(41, 30), Pair(61, 20), Pair(101, 25), - Pair(131, 30), Pair(181, 35), Pair(251, 30), Pair(301, 25), Pair(360, 25)) + val hueToRotations = + listOf( + Pair(0, 35), + Pair(41, 30), + Pair(61, 20), + Pair(101, 25), + Pair(131, 30), + Pair(181, 35), + Pair(251, 30), + Pair(301, 25), + Pair(360, 25) + ) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) @@ -96,8 +119,18 @@ internal class HueVibrantTertiary() : Hue { } internal class HueExpressiveSecondary() : Hue { - val hueToRotations = listOf(Pair(0, 45), Pair(21, 95), Pair(51, 45), Pair(121, 20), - Pair(151, 45), Pair(191, 90), Pair(271, 45), Pair(321, 45), Pair(360, 45)) + val hueToRotations = + listOf( + Pair(0, 45), + Pair(21, 95), + Pair(51, 45), + Pair(121, 20), + Pair(151, 45), + Pair(191, 90), + Pair(271, 45), + Pair(321, 45), + Pair(360, 45) + ) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) @@ -105,8 +138,18 @@ internal class HueExpressiveSecondary() : Hue { } internal class HueExpressiveTertiary() : Hue { - val hueToRotations = listOf(Pair(0, 120), Pair(21, 120), Pair(51, 20), Pair(121, 45), - Pair(151, 20), Pair(191, 15), Pair(271, 20), Pair(321, 120), Pair(360, 120)) + val hueToRotations = + listOf( + Pair(0, 120), + Pair(21, 120), + Pair(51, 20), + Pair(121, 45), + Pair(151, 20), + Pair(191, 15), + Pair(271, 20), + Pair(321, 120), + Pair(360, 120) + ) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) @@ -115,13 +158,18 @@ internal class HueExpressiveTertiary() : Hue { internal interface Chroma { fun get(sourceColor: Cam): Double + + companion object { + val MAX_VALUE = 120.0 + val MIN_VALUE = 0.0 + } } internal class ChromaMaxOut : Chroma { override fun get(sourceColor: Cam): Double { // Intentionally high. Gamut mapping from impossible HCT to sRGB will ensure that // the maximum chroma is reached, even if lower than this constant. - return 130.0 + return Chroma.MAX_VALUE + 10.0 } } @@ -131,6 +179,23 @@ internal class ChromaMultiple(val multiple: Double) : Chroma { } } +internal class ChromaAdd(val amount: Double) : Chroma { + override fun get(sourceColor: Cam): Double { + return sourceColor.chroma + amount + } +} + +internal class ChromaBound( + val baseChroma: Chroma, + val minVal: Double, + val maxVal: Double, +) : Chroma { + override fun get(sourceColor: Cam): Double { + val result = baseChroma.get(sourceColor) + return min(max(result, minVal), maxVal) + } +} + internal class ChromaConstant(val chroma: Double) : Chroma { override fun get(sourceColor: Cam): Double { return chroma @@ -149,109 +214,173 @@ internal class TonalSpec(val hue: Hue = HueSource(), val chroma: Chroma) { val chroma = chroma.get(sourceColor) return Shades.of(hue.toFloat(), chroma.toFloat()).toList() } + + fun getAtTone(sourceColor: Cam, tone: Float): Int { + val hue = hue.get(sourceColor) + val chroma = chroma.get(sourceColor) + return ColorUtils.CAMToColor(hue.toFloat(), chroma.toFloat(), (1000f - tone) / 10f) + } } internal class CoreSpec( - val a1: TonalSpec, - val a2: TonalSpec, - val a3: TonalSpec, - val n1: TonalSpec, - val n2: TonalSpec + val a1: TonalSpec, + val a2: TonalSpec, + val a3: TonalSpec, + val n1: TonalSpec, + val n2: TonalSpec ) enum class Style(internal val coreSpec: CoreSpec) { - SPRITZ(CoreSpec( + SPRITZ( + CoreSpec( a1 = TonalSpec(HueSource(), ChromaConstant(12.0)), a2 = TonalSpec(HueSource(), ChromaConstant(8.0)), a3 = TonalSpec(HueSource(), ChromaConstant(16.0)), n1 = TonalSpec(HueSource(), ChromaConstant(2.0)), n2 = TonalSpec(HueSource(), ChromaConstant(2.0)) - )), - TONAL_SPOT(CoreSpec( + ) + ), + TONAL_SPOT( + CoreSpec( a1 = TonalSpec(HueSource(), ChromaConstant(36.0)), a2 = TonalSpec(HueSource(), ChromaConstant(16.0)), a3 = TonalSpec(HueAdd(60.0), ChromaConstant(24.0)), n1 = TonalSpec(HueSource(), ChromaConstant(6.0)), n2 = TonalSpec(HueSource(), ChromaConstant(8.0)) - )), - VIBRANT(CoreSpec( + ) + ), + VIBRANT( + CoreSpec( a1 = TonalSpec(HueSource(), ChromaMaxOut()), a2 = TonalSpec(HueVibrantSecondary(), ChromaConstant(24.0)), a3 = TonalSpec(HueVibrantTertiary(), ChromaConstant(32.0)), n1 = TonalSpec(HueSource(), ChromaConstant(10.0)), n2 = TonalSpec(HueSource(), ChromaConstant(12.0)) - )), - EXPRESSIVE(CoreSpec( + ) + ), + EXPRESSIVE( + CoreSpec( a1 = TonalSpec(HueAdd(240.0), ChromaConstant(40.0)), a2 = TonalSpec(HueExpressiveSecondary(), ChromaConstant(24.0)), a3 = TonalSpec(HueExpressiveTertiary(), ChromaConstant(32.0)), n1 = TonalSpec(HueAdd(15.0), ChromaConstant(8.0)), n2 = TonalSpec(HueAdd(15.0), ChromaConstant(12.0)) - )), - RAINBOW(CoreSpec( + ) + ), + RAINBOW( + CoreSpec( a1 = TonalSpec(HueSource(), ChromaConstant(48.0)), a2 = TonalSpec(HueSource(), ChromaConstant(16.0)), a3 = TonalSpec(HueAdd(60.0), ChromaConstant(24.0)), n1 = TonalSpec(HueSource(), ChromaConstant(0.0)), n2 = TonalSpec(HueSource(), ChromaConstant(0.0)) - )), - FRUIT_SALAD(CoreSpec( + ) + ), + FRUIT_SALAD( + CoreSpec( a1 = TonalSpec(HueSubtract(50.0), ChromaConstant(48.0)), a2 = TonalSpec(HueSubtract(50.0), ChromaConstant(36.0)), a3 = TonalSpec(HueSource(), ChromaConstant(36.0)), n1 = TonalSpec(HueSource(), ChromaConstant(10.0)), n2 = TonalSpec(HueSource(), ChromaConstant(16.0)) - )), - CONTENT(CoreSpec( + ) + ), + CONTENT( + CoreSpec( a1 = TonalSpec(HueSource(), ChromaSource()), a2 = TonalSpec(HueSource(), ChromaMultiple(0.33)), a3 = TonalSpec(HueSource(), ChromaMultiple(0.66)), n1 = TonalSpec(HueSource(), ChromaMultiple(0.0833)), n2 = TonalSpec(HueSource(), ChromaMultiple(0.1666)) - )), - MONOCHROMATIC(CoreSpec( + ) + ), + MONOCHROMATIC( + CoreSpec( a1 = TonalSpec(HueSource(), ChromaConstant(.0)), a2 = TonalSpec(HueSource(), ChromaConstant(.0)), a3 = TonalSpec(HueSource(), ChromaConstant(.0)), n1 = TonalSpec(HueSource(), ChromaConstant(.0)), n2 = TonalSpec(HueSource(), ChromaConstant(.0)) - )), + ) + ), + CLOCK( + CoreSpec( + a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 20.0, Chroma.MAX_VALUE)), + a2 = TonalSpec(HueAdd(10.0), ChromaBound(ChromaMultiple(0.85), 17.0, 40.0)), + a3 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaAdd(20.0), 50.0, Chroma.MAX_VALUE)), + + // Not Used + n1 = TonalSpec(HueSource(), ChromaConstant(0.0)), + n2 = TonalSpec(HueSource(), ChromaConstant(0.0)) + ) + ), + CLOCK_VIBRANT( + CoreSpec( + a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)), + a2 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)), + a3 = TonalSpec(HueAdd(60.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)), + + // Not Used + n1 = TonalSpec(HueSource(), ChromaConstant(0.0)), + n2 = TonalSpec(HueSource(), ChromaConstant(0.0)) + ) + ) } -class TonalPalette { - val shadeKeys = listOf(10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000) - val allShades: List<Int> - val allShadesMapped: Map<Int, Int> +class TonalPalette +internal constructor( + private val spec: TonalSpec, + seedColor: Int, +) { + val seedCam: Cam = Cam.fromInt(seedColor) + val allShades: List<Int> = spec.shades(seedCam) + val allShadesMapped: Map<Int, Int> = SHADE_KEYS.zip(allShades).toMap() val baseColor: Int - internal constructor(spec: TonalSpec, seedColor: Int) { - val seedCam = Cam.fromInt(seedColor) - allShades = spec.shades(seedCam) - allShadesMapped = shadeKeys.zip(allShades).toMap() - + init { val h = spec.hue.get(seedCam).toFloat() val c = spec.chroma.get(seedCam).toFloat() baseColor = ColorUtils.CAMToColor(h, c, CamUtils.lstarFromInt(seedColor)) } - val s10: Int get() = this.allShades[0] - val s50: Int get() = this.allShades[1] - val s100: Int get() = this.allShades[2] - val s200: Int get() = this.allShades[3] - val s300: Int get() = this.allShades[4] - val s400: Int get() = this.allShades[5] - val s500: Int get() = this.allShades[6] - val s600: Int get() = this.allShades[7] - val s700: Int get() = this.allShades[8] - val s800: Int get() = this.allShades[9] - val s900: Int get() = this.allShades[10] - val s1000: Int get() = this.allShades[11] + // Dynamically computed tones across the full range from 0 to 1000 + fun getAtTone(tone: Float) = spec.getAtTone(seedCam, tone) + + // Predefined & precomputed tones + val s10: Int + get() = this.allShades[0] + val s50: Int + get() = this.allShades[1] + val s100: Int + get() = this.allShades[2] + val s200: Int + get() = this.allShades[3] + val s300: Int + get() = this.allShades[4] + val s400: Int + get() = this.allShades[5] + val s500: Int + get() = this.allShades[6] + val s600: Int + get() = this.allShades[7] + val s700: Int + get() = this.allShades[8] + val s800: Int + get() = this.allShades[9] + val s900: Int + get() = this.allShades[10] + val s1000: Int + get() = this.allShades[11] + + companion object { + val SHADE_KEYS = listOf(10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000) + } } class ColorScheme( - @ColorInt val seed: Int, - val darkTheme: Boolean, - val style: Style = Style.TONAL_SPOT + @ColorInt val seed: Int, + val darkTheme: Boolean, + val style: Style = Style.TONAL_SPOT ) { val accent1: TonalPalette @@ -260,16 +389,14 @@ class ColorScheme( val neutral1: TonalPalette val neutral2: TonalPalette - constructor(@ColorInt seed: Int, darkTheme: Boolean) : - this(seed, darkTheme, Style.TONAL_SPOT) + constructor(@ColorInt seed: Int, darkTheme: Boolean) : this(seed, darkTheme, Style.TONAL_SPOT) @JvmOverloads constructor( - wallpaperColors: WallpaperColors, - darkTheme: Boolean, - style: Style = Style.TONAL_SPOT - ) : - this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style) + wallpaperColors: WallpaperColors, + darkTheme: Boolean, + style: Style = Style.TONAL_SPOT + ) : this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style) val allHues: List<TonalPalette> get() { @@ -301,13 +428,14 @@ class ColorScheme( init { val proposedSeedCam = Cam.fromInt(seed) - val seedArgb = if (seed == Color.TRANSPARENT) { - GOOGLE_BLUE - } else if (style != Style.CONTENT && proposedSeedCam.chroma < 5) { - GOOGLE_BLUE - } else { - seed - } + val seedArgb = + if (seed == Color.TRANSPARENT) { + GOOGLE_BLUE + } else if (style != Style.CONTENT && proposedSeedCam.chroma < 5) { + GOOGLE_BLUE + } else { + seed + } accent1 = TonalPalette(style.coreSpec.a1, seedArgb) accent2 = TonalPalette(style.coreSpec.a2, seedArgb) @@ -316,19 +444,23 @@ class ColorScheme( neutral2 = TonalPalette(style.coreSpec.n2, seedArgb) } - val shadeCount get() = this.accent1.allShades.size + val shadeCount + get() = this.accent1.allShades.size + + val seedTone: Float + get() = 1000f - CamUtils.lstarFromInt(seed) * 10f override fun toString(): String { return "ColorScheme {\n" + - " seed color: ${stringForColor(seed)}\n" + - " style: $style\n" + - " palettes: \n" + - " ${humanReadable("PRIMARY", accent1.allShades)}\n" + - " ${humanReadable("SECONDARY", accent2.allShades)}\n" + - " ${humanReadable("TERTIARY", accent3.allShades)}\n" + - " ${humanReadable("NEUTRAL", neutral1.allShades)}\n" + - " ${humanReadable("NEUTRAL VARIANT", neutral2.allShades)}\n" + - "}" + " seed color: ${stringForColor(seed)}\n" + + " style: $style\n" + + " palettes: \n" + + " ${humanReadable("PRIMARY", accent1.allShades)}\n" + + " ${humanReadable("SECONDARY", accent2.allShades)}\n" + + " ${humanReadable("TERTIARY", accent3.allShades)}\n" + + " ${humanReadable("NEUTRAL", neutral1.allShades)}\n" + + " ${humanReadable("NEUTRAL VARIANT", neutral2.allShades)}\n" + + "}" } companion object { @@ -356,8 +488,8 @@ class ColorScheme( @JvmStatic @JvmOverloads fun getSeedColors(wallpaperColors: WallpaperColors, filter: Boolean = true): List<Int> { - val totalPopulation = wallpaperColors.allColors.values.reduce { a, b -> a + b } - .toDouble() + val totalPopulation = + wallpaperColors.allColors.values.reduce { a, b -> a + b }.toDouble() val totalPopulationMeaningless = (totalPopulation == 0.0) if (totalPopulationMeaningless) { // WallpaperColors with a population of 0 indicate the colors didn't come from @@ -365,51 +497,56 @@ class ColorScheme( // secondary/tertiary colors. // // In this case, the colors are usually from a Live Wallpaper. - val distinctColors = wallpaperColors.mainColors.map { - it.toArgb() - }.distinct().filter { - if (!filter) { - true - } else { - Cam.fromInt(it).chroma >= MIN_CHROMA - } - }.toList() + val distinctColors = + wallpaperColors.mainColors + .map { it.toArgb() } + .distinct() + .filter { + if (!filter) { + true + } else { + Cam.fromInt(it).chroma >= MIN_CHROMA + } + } + .toList() if (distinctColors.isEmpty()) { return listOf(GOOGLE_BLUE) } return distinctColors } - val intToProportion = wallpaperColors.allColors.mapValues { - it.value.toDouble() / totalPopulation - } + val intToProportion = + wallpaperColors.allColors.mapValues { it.value.toDouble() / totalPopulation } val intToCam = wallpaperColors.allColors.mapValues { Cam.fromInt(it.key) } // Get an array with 360 slots. A slot contains the percentage of colors with that hue. val hueProportions = huePopulations(intToCam, intToProportion, filter) // Map each color to the percentage of the image with its hue. - val intToHueProportion = wallpaperColors.allColors.mapValues { - val cam = intToCam[it.key]!! - val hue = cam.hue.roundToInt() - var proportion = 0.0 - for (i in hue - 15..hue + 15) { - proportion += hueProportions[wrapDegrees(i)] + val intToHueProportion = + wallpaperColors.allColors.mapValues { + val cam = intToCam[it.key]!! + val hue = cam.hue.roundToInt() + var proportion = 0.0 + for (i in hue - 15..hue + 15) { + proportion += hueProportions[wrapDegrees(i)] + } + proportion } - proportion - } // Remove any inappropriate seed colors. For example, low chroma colors look grayscale // raising their chroma will turn them to a much louder color that may not have been // in the image. - val filteredIntToCam = if (!filter) intToCam else (intToCam.filter { - val cam = it.value - val proportion = intToHueProportion[it.key]!! - cam.chroma >= MIN_CHROMA && - (totalPopulationMeaningless || proportion > 0.01) - }) + val filteredIntToCam = + if (!filter) intToCam + else + (intToCam.filter { + val cam = it.value + val proportion = intToHueProportion[it.key]!! + cam.chroma >= MIN_CHROMA && + (totalPopulationMeaningless || proportion > 0.01) + }) // Sort the colors by score, from high to low. - val intToScoreIntermediate = filteredIntToCam.mapValues { - score(it.value, intToHueProportion[it.key]!!) - } + val intToScoreIntermediate = + filteredIntToCam.mapValues { score(it.value, intToHueProportion[it.key]!!) } val intToScore = intToScoreIntermediate.entries.toMutableList() intToScore.sortByDescending { it.value } @@ -423,11 +560,12 @@ class ColorScheme( seeds.clear() for (entry in intToScore) { val int = entry.key - val existingSeedNearby = seeds.find { - val hueA = intToCam[int]!!.hue - val hueB = intToCam[it]!!.hue - hueDiff(hueA, hueB) < i - } != null + val existingSeedNearby = + seeds.find { + val hueA = intToCam[int]!!.hue + val hueB = intToCam[it]!!.hue + hueDiff(hueA, hueB) < i + } != null if (existingSeedNearby) { continue } @@ -489,22 +627,22 @@ class ColorScheme( } private fun humanReadable(paletteName: String, colors: List<Int>): String { - return "$paletteName\n" + colors.map { - stringForColor(it) - }.joinToString(separator = "\n") { it } + return "$paletteName\n" + + colors.map { stringForColor(it) }.joinToString(separator = "\n") { it } } private fun score(cam: Cam, proportion: Double): Double { val proportionScore = 0.7 * 100.0 * proportion - val chromaScore = if (cam.chroma < ACCENT1_CHROMA) 0.1 * (cam.chroma - ACCENT1_CHROMA) - else 0.3 * (cam.chroma - ACCENT1_CHROMA) + val chromaScore = + if (cam.chroma < ACCENT1_CHROMA) 0.1 * (cam.chroma - ACCENT1_CHROMA) + else 0.3 * (cam.chroma - ACCENT1_CHROMA) return chromaScore + proportionScore } private fun huePopulations( - camByColor: Map<Int, Cam>, - populationByColor: Map<Int, Double>, - filter: Boolean = true + camByColor: Map<Int, Cam>, + populationByColor: Map<Int, Double>, + filter: Boolean = true ): List<Double> { val huePopulation = List(size = 360, init = { 0.0 }).toMutableList() diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt index 5b6a83c24e3d..c279053e6daf 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -109,6 +109,9 @@ interface ClockEvents { /** Call whenever the locale changes */ fun onLocaleChanged(locale: Locale) {} + val isReactiveToTone + get() = true + /** Call whenever the color palette should update */ fun onColorPaletteChanged(resources: Resources) {} @@ -137,6 +140,12 @@ interface ClockAnimations { fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) {} /** + * Runs when swiping clock picker, swipingFraction: 1.0 -> clock is scaled up in the preview, + * 0.0 -> clock is scaled down in the shade; previewRatio is previewSize / screenSize + */ + fun onPickerCarouselSwiping(swipingFraction: Float, previewRatio: Float) {} + + /** * Whether this clock has a custom position update animation. If true, the keyguard will call * `onPositionUpdated` to notify the clock of a position update animation. If false, a default * animation will be used (e.g. a simple translation). @@ -158,8 +167,12 @@ interface ClockFaceEvents { val hasCustomWeatherDataDisplay: Boolean get() = false - /** Region Darkness specific to the clock face */ - fun onRegionDarknessChanged(isDark: Boolean) {} + /** + * Region Darkness specific to the clock face. + * - isRegionDark = dark theme -> clock should be light + * - !isRegionDark = light theme -> clock should be dark + */ + fun onRegionDarknessChanged(isRegionDark: Boolean) {} /** * Call whenever font settings change. Pass in a target font size in pixels. The specific clock diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java index 4e70455f9b8a..59911b233e80 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java @@ -53,10 +53,6 @@ public interface NotificationSwipeActionHelper { /** Returns true if the gesture should be rejected. */ boolean isFalseGesture(); - public boolean swipedFarEnough(float translation, float viewSize); - - public boolean swipedFastEnough(float translation, float velocity); - @ProvidesInterface(version = SnoozeOption.VERSION) public interface SnoozeOption { public static final int VERSION = 2; diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml index 74b3d39bd050..2fd9cc025844 100644 --- a/packages/SystemUI/res-keyguard/values-mr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml @@ -32,7 +32,7 @@ <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • सावकाश चार्ज होत आहे"</string> <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • बॅटरीचे संरक्षण करण्यासाठी चार्जिंग ऑप्टिमाइझ केले आहे"</string> <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिंगच्या ॲक्सेसरीसंबंधित समस्या"</string> - <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"अनलॉक करण्यासाठी मेनू दाबा."</string> + <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"अनलॉक करण्यासाठी मेनू प्रेस करा."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक केले"</string> <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"सिम नाही"</string> <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"सिम जोडा."</string> diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml index abc00056809a..f0c20fd0803a 100644 --- a/packages/SystemUI/res-keyguard/values-nb/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml @@ -47,8 +47,8 @@ <string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"PIN-området for SIM-kortet"</string> <string name="keyguard_accessibility_sim_puk_area" msgid="5537294043180237374">"PUK-området for SIM-kortet"</string> <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Slett"</string> - <string name="disable_carrier_button_text" msgid="7153361131709275746">"Deaktiver e-SIM-kortet"</string> - <string name="error_disable_esim_title" msgid="3802652622784813119">"Kan ikke deaktivere e-SIM-kortet"</string> + <string name="disable_carrier_button_text" msgid="7153361131709275746">"Deaktiver eSIM-kortet"</string> + <string name="error_disable_esim_title" msgid="3802652622784813119">"Kan ikke deaktivere eSIM-kortet"</string> <string name="error_disable_esim_msg" msgid="2441188596467999327">"E-SIM-kortet kan ikke deaktiveres på grunn av en feil."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Feil mønster"</string> @@ -57,7 +57,7 @@ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Prøv på nytt om # sekund.}other{Prøv på nytt om # sekunder.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Skriv inn PIN-koden for SIM-kortet."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Skriv inn PIN-koden for SIM-kortet «<xliff:g id="CARRIER">%1$s</xliff:g>»."</string> - <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Deaktiver e-SIM-kortet for å bruke enheten uten mobiltjeneste."</string> + <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Deaktiver eSIM-kortet for å bruke enheten uten mobiltjeneste."</string> <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM-kortet er nå deaktivert. Skriv inn PUK-koden for å fortsette. Ta kontakt med operatøren for mer informasjon."</string> <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM-kortet «<xliff:g id="CARRIER">%1$s</xliff:g>» er nå deaktivert. Skriv inn PUK-koden for å fortsette. Ta kontakt med operatøren for mer informasjon."</string> <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Tast inn ønsket PIN-kode"</string> diff --git a/packages/SystemUI/res-product/values-mr/strings.xml b/packages/SystemUI/res-product/values-mr/strings.xml index feb960456790..33c3eb4e46bc 100644 --- a/packages/SystemUI/res-product/values-mr/strings.xml +++ b/packages/SystemUI/res-product/values-mr/strings.xml @@ -21,8 +21,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="dock_alignment_slow_charging" product="default" msgid="6997633396534416792">"फास्ट चार्ज करण्यासाठी फोन पुन्हा अलाइन करा"</string> <string name="dock_alignment_not_charging" product="default" msgid="3980752926226749808">"वायरलेस पद्धतीने चार्ज करण्यासाठी फोन पुन्हा अलाइन करा"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"Android TV डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी बटण दाबा."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="5693904520452332224">"डिव्हाइस लवकरच बंद होणार आहे; ते सुरू ठेवण्यासाठी दाबा."</string> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"Android TV डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी बटण प्रेस करा."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="5693904520452332224">"डिव्हाइस लवकरच बंद होणार आहे; ते सुरू ठेवण्यासाठी प्रेस करा."</string> <string name="keyguard_missing_sim_message" product="tablet" msgid="408124574073032188">"टॅबलेटमध्ये सिम नाही."</string> <string name="keyguard_missing_sim_message" product="default" msgid="2605468359948247208">"फोनमध्ये सिम नाही."</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="6278551068943958651">"पिन कोड जुळत नाहीत"</string> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 2871cdf6f9f6..4048a39344bd 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -64,7 +64,8 @@ android:layout_height="@dimen/keyguard_affordance_fixed_height" android:layout_width="@dimen/keyguard_affordance_fixed_width" android:layout_gravity="bottom|start" - android:scaleType="center" + android:scaleType="fitCenter" + android:padding="@dimen/keyguard_affordance_fixed_padding" android:tint="?android:attr/textColorPrimary" android:background="@drawable/keyguard_bottom_affordance_bg" android:foreground="@drawable/keyguard_bottom_affordance_selected_border" @@ -77,7 +78,8 @@ android:layout_height="@dimen/keyguard_affordance_fixed_height" android:layout_width="@dimen/keyguard_affordance_fixed_width" android:layout_gravity="bottom|end" - android:scaleType="center" + android:scaleType="fitCenter" + android:padding="@dimen/keyguard_affordance_fixed_padding" android:tint="?android:attr/textColorPrimary" android:background="@drawable/keyguard_bottom_affordance_bg" android:foreground="@drawable/keyguard_bottom_affordance_selected_border" diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml index bb82f91fe2a0..11ec02575e97 100644 --- a/packages/SystemUI/res/layout/notification_snooze.xml +++ b/packages/SystemUI/res/layout/notification_snooze.xml @@ -46,6 +46,7 @@ android:layout_toEndOf="@+id/snooze_option_default" android:layout_centerVertical="true" android:paddingTop="1dp" + android:importantForAccessibility="yes" android:tint="#9E9E9E" /> <TextView diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 73a77bdbd36c..bb2f0f669e45 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrotingwisselaar"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Vergroot die hele skerm"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Vergroot \'n deel van die skerm"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Wissel"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Maak vergrotinginstellings oop"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Sleep hoek om grootte te verander"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Laat diagonale rollees toe"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Klein"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Groot"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Klaar"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Wysig"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Vergrootglasvensterinstellings"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 4159cca41d48..dd863ac0ac10 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -69,8 +69,7 @@ <string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"ዩኤስቢ አንቃ"</string> <string name="learn_more" msgid="4690632085667273811">"የበለጠ ለመረዳት"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገጽ እይታ"</string> - <!-- no translation found for global_action_smart_lock_disabled (6286551337177954859) --> - <skip /> + <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"መክፈትን አራዝም ተሰናክሏል"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ቅጽበታዊ ገጽ እይታን ወደ የስራ መገለጫ በማስቀመጥ ላይ…"</string> @@ -833,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"የማጉላት ማብሪያ/ማጥፊያ"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ሙሉ ገጽ እይታን ያጉሉ"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"የማያ ገጹን ክፍል አጉላ"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ማብሪያ/ማጥፊያ"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"የማጉያ ቅንብሮችን ክፈት"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"መጠን ለመቀየር ጠርዙን ይዘው ይጎትቱ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ሰያፍ ሽብለላን ፍቀድ"</string> @@ -850,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"መካከለኛ"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"ትንሽ"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ትልቅ"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ተከናውኗል"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"አርትዕ"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"የማጉያ መስኮት ቅንብሮች"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 17c3d0f75f63..1751e7803724 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"مفتاح تبديل وضع التكبير"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"تكبير الشاشة كلها"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"تكبير جزء من الشاشة"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"تبديل"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"فتح إعدادات التكبير"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"اسحب الزاوية لتغيير الحجم."</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"السماح بالتمرير القطري"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"متوسط"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"صغير"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"كبير"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"تم"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"تعديل"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"إعدادات نافذة مكبّر الشاشة"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{تمت إضافة عنصر تحكّم واحد.}zero{تمت إضافة # عنصر تحكّم.}two{تمت إضافة عنصرَي تحكّم.}few{تمت إضافة # عناصر تحكّم.}many{تمت إضافة # عنصر تحكّم.}other{تمت إضافة # عنصر تحكّم.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"تمت الإزالة"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"هل تريد إضافة \"<xliff:g id="APPNAME">%s</xliff:g>\"؟"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"يمكن لتطبيق \"<xliff:g id="APPNAME">%s</xliff:g>\" اختيار المحتوى وعناصر التحكّم التي تظهر هنا."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"هل تريد إزالة عناصر التحكّم في \"<xliff:g id="APPNAME">%s</xliff:g>\"؟"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"تمت الإضافة إلى المفضّلة"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"تمت الإضافة إلى المفضّلة، الموضع <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 95cfcb41a1c0..9a6ab18a52e2 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"বিবৰ্ধনৰ ছুইচ"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"পূৰ্ণ স্ক্ৰীন বিবৰ্ধন কৰক"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্ৰীনৰ কিছু অংশ বিবৰ্ধন কৰক"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ছুইচ"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"বিবৰ্ধন কৰাৰ ছেটিং খোলক"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"আকাৰ সলনি কৰিবলৈ চুককেইটা টানি আনি এৰক"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"কৰ্ণডালৰ দিশত স্ক্ৰ’ল কৰাৰ সুবিধা"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"মধ্যমীয়া"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"সৰু"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ডাঙৰ"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"কৰা হ’ল"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"সম্পাদনা কৰক"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"বিবৰ্ধকৰ ৱিণ্ড’ৰ ছেটিং"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 7e26882337c9..8834693c1117 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Böyütmə dəyişdiricisi"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekranı böyüdün"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran hissəsinin böyüdülməsi"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Dəyişdirici"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Böyütmə ayarlarını açın"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Ölçüsünü dəyişmək üçün küncündən sürüşdürün"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diaqonal sürüşdürməyə icazə verin"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Orta"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Kiçik"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Böyük"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Hazırdır"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Redaktə edin"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Böyüdücü pəncərə ayarları"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 6f36211f8e4a..3f204accf6c0 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prelazak na drugi režim uvećanja"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećajte ceo ekran"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećajte deo ekrana"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pređi"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvori podešavanja uvećanja"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Prevucite ugao da biste promenili veličinu"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dozvoli dijagonalno skrolovanje"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednje"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Malo"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Veliko"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Gotovo"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Izmeni"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Podešavanja prozora za uvećanje"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 0b3042830634..5867d9230102 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Пераключальнік павелічэння"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Павялічыць увесь экран"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Павялічыць частку экрана"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Пераключальнік"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Адкрыць налады павелічэння"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Каб змяніць памер, перацягніце вугал"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дазволіць прагортванне па дыяганалі"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Сярэдні"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Дробны"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Вялікі"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Гатова"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Змяніць"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Налады акна лупы"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Дададзены # элемент кіравання.}one{Дададзена # элемента кіравання.}few{Дададзена # элементы кіравання.}many{Дададзена # элементаў кіравання.}other{Дададзена # элемента кіравання.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Выдалена"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Дадаць праграму \"<xliff:g id="APPNAME">%s</xliff:g>\"?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"У праграме \"<xliff:g id="APPNAME">%s</xliff:g>\" можна выбраць налады і змесціва, якія будуць тут паказвацца."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Выдаліць налады для <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Дададзена ў абранае"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Дададзена ў абранае, пазіцыя <xliff:g id="NUMBER">%d</xliff:g>"</string> @@ -1066,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"змяніць"</string> <string name="add" msgid="81036585205287996">"Дадаць"</string> <string name="manage_users" msgid="1823875311934643849">"Кіраванне карыстальнікамі"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Гэта апавяшчэнне нельга перацягнуць на падзелены экран."</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Сетка Wi‑Fi недаступная"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Прыярытэтны рэжым"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будзільнік зададзены"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index dd4c4e8709a1..046ebfce4bb2 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Превключване на увеличението"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличаване на целия екран"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличаване на част от екрана"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Превключване"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отваряне на настройките за увеличението"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Плъзнете ъгъла за преоразмеряване"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Разрешаване на диагонално превъртане"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Среден"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Малък"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Голям"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Готово"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Редактиране"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Настройки за инструмента за увеличаване на прозорци"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"редактиране"</string> <string name="add" msgid="81036585205287996">"Добавяне"</string> <string name="manage_users" msgid="1823875311934643849">"Управление на потребителите"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Това известие не поддържа плъзгане за разделяне на екрана"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi не е налице"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будилникът е зададен"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 1d7d607c43ba..f44029768cba 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"বড় করে দেখার সুইচ"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"সম্পূর্ণ স্ক্রিন বড় করে দেখা"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্রিনের কিছুটা অংশ বড় করুন"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"বদল করুন"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"বড় করে দেখার সেটিংস খুলুন"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ছোট বড় করার জন্য কোণ টেনে আনুন"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"কোণাকুণি স্ক্রল করার অনুমতি দেওয়া"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"মাঝারি"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"ছোট"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"বড়"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"হয়ে গেছে"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"এডিট করুন"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"\'ম্যাগনিফায়ার উইন্ডো\' সেটিংস"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"এডিট করতে"</string> <string name="add" msgid="81036585205287996">"যোগ করুন"</string> <string name="manage_users" msgid="1823875311934643849">"ব্যবহারকারীদের ম্যানেজ করুন"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"\'স্প্লিটস্ক্রিন\' মোডে এই বিজ্ঞপ্তি টেনে আনা যাবে না"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ওয়াই-ফাই উপলভ্য নেই"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"প্রায়োরিটি মোড"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"অ্যালার্ম সেট করা হয়েছে"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 62eafb401050..b0638ca2fb6b 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prekidač za uvećavanje"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećavanje prikaza preko cijelog ekrana"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećavanje dijela ekrana"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prekidač"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvori postavke uvećavanja"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Prevucite ugao da promijenite veličinu"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dozvoli dijagonalno klizanje"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednje"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Malo"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Veliko"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Gotovo"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Uredi"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Postavke prozora povećala"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 42649d125436..f85c7b45d522 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Canvia al mode d\'ampliació"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Amplia la pantalla completa"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplia una part de la pantalla"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Canvia"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Obre la configuració de l\'ampliació"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrossega el cantó per canviar la mida"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permet el desplaçament en diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Normal"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Petit"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Gran"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Fet"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edita"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuració de la finestra de la lupa"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 13b87f18891d..2c7bea2b3dc8 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Přepínač zvětšení"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zvětšit celou obrazovku"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zvětšit část obrazovky"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Přepnout"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otevřít nastavení zvětšení"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Velikost změníte přetažením rohu"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Povolit diagonální posouvání"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Střední"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Malý"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Velký"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Hotovo"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Upravit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavení okna zvětšení"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Byl přidán # ovládací prvek.}few{Byly přidány # ovládací prvky.}many{Bylo přidáno # ovládacího prvku.}other{Bylo přidáno # ovládacích prvků.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Odstraněno"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Přidat aplikaci <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Aplikace <xliff:g id="APPNAME">%s</xliff:g> může vybrat, které ovládací prvky a obsah se zde zobrazí."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Odstranit ovládací prvky aplikace <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Přidáno do oblíbených"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Přidáno do oblíbených na pozici <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 815b40224beb..f066e6150fda 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Skift forstørrelsestilstand"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstør hele skærmen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstør en del af skærmen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Skift"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Åbn indstillinger for forstørrelse"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Træk i hjørnet for at justere størrelsen"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Tillad diagonal rulning"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mellem"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Lille"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Stor"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Udfør"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Rediger"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Indstillinger for lupvindue"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# styringselement er tilføjet.}one{# styringselement er tilføjet.}other{# styringselementer er tilføjet.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Fjernet"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vil du tilføje <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan vælge, hvilke styringselementer og hvilket indhold der skal vises her."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vil du fjerne styringselementerne for <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Angivet som favorit"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Angivet som favorit. Position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index a3dcf62a3b4d..2c6b22f709df 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrößerungsschalter"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ganzen Bildschirm vergrößern"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schalter"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Vergrößerungseinstellungen öffnen"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Zum Anpassen der Größe Ecke ziehen"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diagonales Scrollen erlauben"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mittel"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Klein"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Groß"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Fertig"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Bearbeiten"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Einstellungen für das Vergrößerungsfenster"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"bearbeiten"</string> <string name="add" msgid="81036585205287996">"Hinzufügen"</string> <string name="manage_users" msgid="1823875311934643849">"Nutzer verwalten"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Diese Benachrichtigung lässt sich nicht auf einen geteilten Bildschirm ziehen"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN nicht verfügbar"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritätsmodus"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wecker gestellt"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 4c76e1712ee6..9a8c8ab49e72 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Εναλλαγή μεγιστοποίησης"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Μεγέθυνση πλήρους οθόνης"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Μεγέθυνση μέρους της οθόνης"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Εναλλαγή"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Άνοιγμα ρυθμίσεων μεγιστοποίησης"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Σύρετε τη γωνία για αλλαγή μεγέθους"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Να επιτρέπεται η διαγώνια κύλιση"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Μέτριο"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Μικρό"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Μεγάλο"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Τέλος"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Επεξεργασία"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ρυθμίσεις παραθύρου μεγεθυντικού φακού"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 80868289e985..2c9909b77e25 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index c53db1824d0a..4479c91357b0 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string> @@ -849,6 +848,7 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string> + <string name="accessibility_magnification_fullscreen" msgid="5043514702759201964">"Full screen"</string> <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string> @@ -1086,7 +1086,7 @@ <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="log_access_confirmation_title" msgid="4843557604739943395">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string> <string name="log_access_confirmation_allow" msgid="752147861593202968">"Allow one-time access"</string> - <string name="log_access_confirmation_deny" msgid="2389461495803585795">"Don’t allow"</string> + <string name="log_access_confirmation_deny" msgid="2389461495803585795">"Don\'t allow"</string> <string name="log_access_confirmation_body" msgid="6883031912003112634">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string> <string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Learn more"</string> <string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Learn more at <xliff:g id="URL">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 80868289e985..2c9909b77e25 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 80868289e985..2c9909b77e25 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 11c7db8cea74..24f09e2f21f9 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Open magnification settings"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Drag corner to resize"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Allow diagonal scrolling"</string> @@ -849,6 +848,7 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medium"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Small"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Large"</string> + <string name="accessibility_magnification_fullscreen" msgid="5043514702759201964">"Full screen"</string> <string name="accessibility_magnification_done" msgid="263349129937348512">"Done"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 8f3fc6f0dadb..4ffe070ec453 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor de ampliación"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Interruptor"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir la configuración de ampliación"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastra la esquina para cambiar el tamaño"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir desplazamiento en diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mediano"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeño"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Listo"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración de la ventana de ampliación"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"editar"</string> <string name="add" msgid="81036585205287996">"Agregar"</string> <string name="manage_users" msgid="1823875311934643849">"Administrar usuarios"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificación no admite arrastrar entre pantallas divididas"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"La red Wi-Fi no está disponible"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioridad"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Se estableció la alarma"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index a4c4dd05ab4f..5d19759ed46d 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Botón para cambiar el modo de ampliación"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir ajustes de ampliación"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastra la esquina para cambiar el tamaño"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir desplazamiento en diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mediano"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeño"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Listo"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración de la ventana de la lupa"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 128806070ec1..5573a40c73f1 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suurenduse lüliti"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Täisekraani suurendamine"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekraanikuva osa suurendamine"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaheta"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ava suurendamisseaded"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Suuruse muutmiseks lohistage nurka"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Luba diagonaalne kerimine"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Keskmine"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Väike"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Suur"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Valmis"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Muuda"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Luubi akna seaded"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"muutmine"</string> <string name="add" msgid="81036585205287996">"Lisa"</string> <string name="manage_users" msgid="1823875311934643849">"Kasutajate haldamine"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"See märguanne ei toeta jagatud ekraanikuvale lohistamist."</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi pole saadaval"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režiim Prioriteetne"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm on määratud"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 4873d88ce0c9..15e236cda8d2 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Lupa aplikatzeko botoia"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Handitu pantaila osoa"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Handitu pantailaren zati bat"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botoia"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ireki luparen ezarpenak"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastatu izkina bat tamaina aldatzeko"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Eman diagonalki gora eta behera egiteko aukera erabiltzeko baimena"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Ertaina"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Txikia"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Handia"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Eginda"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editatu"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Luparen leihoaren ezarpenak"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index f62ab7767e11..47ebc9eadd0f 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"کلید درشتنمایی"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"درشتنمایی تمامصفحه"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"درشتنمایی بخشی از صفحه"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"کلید"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"باز کردن تنظیمات درشتنمایی"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"برای تغییر اندازه، گوشه را بکشید"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"مجاز کردن پیمایش قطری"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"متوسط"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"کوچک"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"بزرگ"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"تمام"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ویرایش"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"تنظیمات پنجره ذرهبین"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"ویرایش کردن"</string> <string name="add" msgid="81036585205287996">"افزودن"</string> <string name="manage_users" msgid="1823875311934643849">"مدیریت کاربران"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"این اعلان از عملکرد کشیدن به صفحهٔ دونیمه پشتیبانی نمیکند"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi دردسترس نیست"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"حالت اولویت"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"زنگ ساعت تنظیم شد"</string> @@ -1087,7 +1087,7 @@ <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="log_access_confirmation_title" msgid="4843557604739943395">"به <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> اجازه میدهید به همه گزارشهای دستگاه دسترسی داشته باشد؟"</string> <string name="log_access_confirmation_allow" msgid="752147861593202968">"مجاز کردن دسترسی یکباره"</string> - <string name="log_access_confirmation_deny" msgid="2389461495803585795">"اجازه نمیدهم"</string> + <string name="log_access_confirmation_deny" msgid="2389461495803585795">"اجازه ندادن"</string> <string name="log_access_confirmation_body" msgid="6883031912003112634">"گزارشهای دستگاه آنچه را در دستگاهتان رخ میدهد ثبت میکند. برنامهها میتوانند از این گزارشها برای پیدا کردن مشکلات و رفع آنها استفاده کنند.\n\nبرخیاز گزارشها ممکن است حاوی اطلاعات حساس باشند، بنابراین فقط به برنامههای مورداعتمادتان اجازه دسترسی به همه گزارشهای دستگاه را بدهید. \n\nاگر به این برنامه اجازه ندهید به همه گزارشهای دستگاه دسترسی داشته باشد، همچنان میتواند به گزارشهای خودش دسترسی داشته باشد. سازنده دستگاه نیز ممکن است همچنان بتواند به برخیاز گزارشها یا اطلاعات دستگاهتان دسترسی داشته باشد."</string> <string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"بیشتر بدانید"</string> <string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"در <xliff:g id="URL">%s</xliff:g> اطلاعات بیشتری دریافت کنید"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index e478bd2c1053..9d61ec37f4d3 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suurennusvalinta"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Koko näytön suurennus"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Suurenna osa näytöstä"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaihda"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Avaa suurennusasetukset"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Muuta kokoa vetämällä kulmaa"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diagonaalisen vierittämisen salliminen"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Keskitaso"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Pieni"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Suuri"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Valmis"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Muokkaa"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ikkunan suurennuksen asetukset"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# säädin lisätty.}other{# säädintä lisätty.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Poistettu"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Lisätäänkö <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> voi valita täällä näkyvät ohjaimet ja sisällön."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Poistetaanko säätimet: <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Lisätty suosikkeihin"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Lisätty suosikkeihin sijalle <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index bb26ad4daf08..7cede1f3e5c8 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -258,7 +258,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correction des couleurs"</string> - <string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"Taille de la police"</string> + <string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"Taille de police"</string> <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gérer les utilisateurs"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Terminé"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fermer"</string> @@ -574,7 +574,7 @@ <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"paramètres des notifications"</string> <string name="notification_menu_snooze_description" msgid="4740133348901973244">"options de répétition des notifications"</string> - <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Me rappeler"</string> + <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Me le rappeler"</string> <string name="snooze_undo" msgid="2738844148845992103">"Annuler"</string> <string name="snoozed_for_time" msgid="7586689374860469469">"Reporté pour <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string> <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}many{# d\'heures}other{# heures}}"</string> @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Commutateur d\'agrandissement"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir la totalité de l\'écran"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Commutateur"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ouvrir les paramètres d\'agrandissement"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Faire glisser le coin pour redimensionner"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Autoriser le défilement en diagonale"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Moyenne"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Petite"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"OK"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Modifier"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Paramètres de la fenêtre de loupe"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# de commandes ajoutées.}other{# commandes ajoutées.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ajouter <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> peut définir les commandes et le contenu qui s\'affiche ici."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Retirer les commandes pour <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index fb0d42cc005c..e8e88474818f 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Changer de mode d\'agrandissement"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir tout l\'écran"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Changer"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ouvrir les paramètres d\'agrandissement"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Faire glisser le coin pour redimensionner"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Autoriser le défilement diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Moyen"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Petit"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grand"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"OK"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Modifier"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Paramètres de la fenêtre d\'agrandissement"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"modifier"</string> <string name="add" msgid="81036585205287996">"Ajouter"</string> <string name="manage_users" msgid="1823875311934643849">"Gérer les utilisateurs"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Impossible de faire glisser cette notification vers l\'écran partagé"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponible"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritaire"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme réglée"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index ac8acde485ba..1cdb66cbc6e5 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor do modo de ampliación"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplía parte da pantalla"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir configuración da ampliación"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastrar a esquina para cambiar o tamaño"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir desprazamento diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mediano"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeno"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Feito"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración da ventá da lupa"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Engadiuse # control.}other{Engadíronse # controis.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Quitouse"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Queres engadir <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> pode escoller os controis e o contido que se mostrarán aquí."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Queres quitar os controis de <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Está entre os controis favoritos"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está entre os controis favoritos (posición: <xliff:g id="NUMBER">%d</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 1267200dd762..8d945cea3ff2 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"મોટું કરવાની સુવિધાવાળી સ્વિચ"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"પૂર્ણ સ્ક્રીનને મોટી કરો"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"સ્ક્રીનનો કોઈ ભાગ મોટો કરો"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"સ્વિચ"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"મોટા કરવાના સેટિંગ ખોલો"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"કદ બદલવા માટે ખૂણો ખેંચો"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ડાયગોનલ સ્ક્રોલિંગને મંજૂરી આપો"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"મધ્યમ"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"નાનું"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"મોટું"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"થઈ ગયું"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ફેરફાર કરો"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"મેગ્નિફાયર વિન્ડોના સેટિંગ"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index f1ff61687402..9fb299687a7b 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -816,7 +816,7 @@ <string name="privacy_type_location" msgid="7991481648444066703">"जगह"</string> <string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफ़ोन"</string> <string name="privacy_type_media_projection" msgid="8136723828804251547">"स्क्रीन रिकॉर्डिंग"</string> - <string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string> + <string name="music_controls_no_title" msgid="4166497066552290938">"कोई टाइटल नहीं"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string> <string name="font_scaling_dialog_title" msgid="6273107303850248375">"फ़ॉन्ट का साइज़"</string> <string name="font_scaling_smaller" msgid="1012032217622008232">"छोटा करें"</string> @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ज़ूम करने की सुविधा वाला स्विच"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फ़ुल स्क्रीन को ज़ूम करें"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीन के किसी हिस्से को ज़ूम करें"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ज़ूम करने की सुविधा वाली सेटिंग खोलें"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"साइज़ बदलने के लिए, कोने को खींचें और छोड़ें"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"तिरछी दिशा में स्क्रोल करने की अनुमति दें"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"मध्यम"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"छोटा"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"बड़ा"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"हो गया"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"बदलाव करें"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ज़ूम करने की सुविधा वाली विंडो से जुड़ी सेटिंग"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 4ece4b61478c..f9fabaa87f05 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prebacivanje povećavanja"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povećajte cijeli zaslon"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povećaj dio zaslona"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prebacivanje"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvori postavke povećavanja"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Povucite kut da biste promijenili veličinu"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dopusti dijagonalno pomicanje"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednja"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Mala"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Velika"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Gotovo"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Uredi"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Postavke prozora povećala"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 8d38e1fdaf2c..9bdd52b9a91c 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Nagyításváltó"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"A teljes képernyő felnagyítása"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Képernyő bizonyos részének nagyítása"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Váltás"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Nagyítási beállítások megnyitása"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Az átméretezéshez húzza a kívánt sarkot"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Átlós görgetés engedélyezése"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Közepes"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Kicsi"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Nagy"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Kész"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Szerkesztés"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nagyítóablak beállításai"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index ed4b312af3b1..b8811e29dd16 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Խոշորացման փոփոխություն"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Խոշորացնել ամբողջ էկրանը"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Խոշորացնել էկրանի որոշակի հատվածը"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Փոխել"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Բացել խոշորացման կարգավորումները"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Քաշեք անկյունը՝ չափը փոխելու համար"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Թույլատրել անկյունագծով ոլորումը"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Միջին"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Փոքր"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Մեծ"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Պատրաստ է"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Փոփոխել"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Խոշորացույցի պատուհանի կարգավորումներ"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Ավելացվեց կառավարման # տարր։}one{Ավելացվեց կառավարման # տարր։}other{Ավելացվեց կառավարման # տարր։}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Հեռացված է"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ավելացնե՞լ <xliff:g id="APPNAME">%s</xliff:g> հավելվածը"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> հավելվածը կարող է ընտրել, թե որ կարգավորումները և ինչ բովանդակություն ցուցադրվեն այստեղ։"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Հեռացնե՞լ <xliff:g id="APPNAME">%s</xliff:g> հավելվածի համար կարգավորումները։"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ավելացված է ընտրանիում"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ավելացված է ընտրանիում, դիրքը՝ <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 72f715835f2c..254844d2c672 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Tombol pembesaran"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Memperbesar tampilan layar penuh"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Perbesar sebagian layar"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Alihkan"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Buka setelan pembesaran"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Tarik pojok persegi untuk mengubah ukuran"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Izinkan scrolling diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Sedang"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Kecil"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Besar"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Selesai"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Setelan jendela kaca pembesar"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index d84e544d99af..a78cac2a0cd1 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Stækkunarrofi"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Stækka allan skjáinn"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Stækka hluta skjásins"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Rofi"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Opna stillingar stækkunar"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Dragðu horn til að breyta stærð"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Leyfa skáflettingu"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Miðlungs"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Lítið"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Stórt"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Lokið"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Breyta"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Stillingar stækkunarglugga"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index d103e41d61bd..e880640718af 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -264,7 +264,7 @@ <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Chiudi"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Connesso"</string> <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Connesso, batteria al <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="quick_settings_connecting" msgid="2381969772953268809">"Connessione..."</string> + <string name="quick_settings_connecting" msgid="2381969772953268809">"Connessione in corso..."</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Attivazione…"</string> <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Risp. dati attivo"</string> @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Opzione Ingrandimento"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ingrandisci l\'intero schermo"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ingrandisci parte dello schermo"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Opzione"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Apri le impostazioni di ingrandimento"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Trascina l\'angolo per ridimensionare"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Consenti lo scorrimento diagonale"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medio"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Piccolo"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Fine"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Modifica"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Impostazioni della finestra di ingrandimento"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controllo aggiunto.}many{# controlli aggiunti.}other{# controlli aggiunti.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vuoi aggiungere <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"L\'app <xliff:g id="APPNAME">%s</xliff:g> potrà scegliere quali controlli e contenuti visualizzare qui."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vuoi rimuovere i controlli per l\'app <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Preferito, posizione <xliff:g id="NUMBER">%d</xliff:g>"</string> @@ -896,7 +896,7 @@ <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vuoi visualizzare e controllare i dispositivi dalla schermata di blocco?"</string> <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Puoi aggiungere impostazioni alla schermata di blocco per i tuoi dispositivi esterni.\n\nL\'app del tuo dispositivo potrebbe consentirti di controllare alcuni dispositivi senza dover sbloccare il tuo telefono o tablet.\n\nPuoi apportare modifiche in qualsiasi momento in Impostazioni."</string> <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Vuoi controllare i dispositivi dalla schermata di blocco?"</string> - <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Puoi controllare alcuni dispositivi senza sbloccare il telefono o il tablet. L\'app del dispositivo determina quali dispositivi possono essere controllati in questo modo."</string> + <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Puoi controllare alcuni dispositivi senza sbloccare il telefono o il tablet. L\'app del tuo dispositivo determina quali dispositivi possono essere controllati in questo modo."</string> <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, grazie"</string> <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sì"</string> <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Il PIN contiene lettere o simboli"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 8c9667c36b62..80a8ff90e087 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"מעבר למצב הגדלה"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"הגדלה של המסך המלא"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"הגדלת חלק מהמסך"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"מעבר"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"פתיחת הגדרות ההגדלה"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"צריך לגרור את הפינה כדי לשנות את הגודל"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"הפעלת גלילה באלכסון"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"בינוני"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"קטן"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"גדול"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"סיום"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"עריכה"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ההגדרות של חלון ההגדלה"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 2fb65a88c1b1..175d4ac4553b 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"拡大スイッチ"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"画面全体を拡大します"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"画面の一部を拡大します"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"スイッチ"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"画面の拡大設定を開く"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"サイズを変更するには角をドラッグ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"斜めスクロールを許可"</string> @@ -849,13 +848,15 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"中"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"小"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"大"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"完了"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"編集"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"拡大鏡ウィンドウの設定"</string> <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"タップしてユーザー補助機能を開きます。ボタンのカスタマイズや入れ替えを [設定] で行えます。\n\n"<annotation id="link">"設定を表示"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ボタンを一時的に非表示にするには、端に移動させてください"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"元に戻す"</string> - <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> 個のショートカットを削除"</string> + <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> のショートカットを削除"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# 個のショートカットを削除}other{# 個のショートカットを削除}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"左上に移動"</string> <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"右上に移動"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# 件のコントロールを追加しました。}other{# 件のコントロールを追加しました。}}"</string> <string name="controls_removed" msgid="3731789252222856959">"削除済み"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> を追加しますか?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> はここに表示されるコントロールとコンテンツを選択できます。"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> のコントロールを削除しますか?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"お気に入りに追加済み"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"お気に入りに追加済み、位置: <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 67852eae3c8f..7538410bd72e 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"გადიდების გადართვა"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"გაადიდეთ სრულ ეკრანზე"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ეკრანის ნაწილის გადიდება"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"გადართვა"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"გახსენით გადიდების პარამეტრები"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ჩავლებით გადაიტანეთ კუთხე ზომის შესაცვლელად"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"დიაგონალური გადახვევის დაშვება"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"საშუალო"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"პატარა"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"დიდი"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"მზადაა"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"რედაქტირება"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"გადიდების ფანჯრის პარამეტრები"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index fb0688dcdc62..ac73680b31c1 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Ұлғайту режиміне ауыстырғыш"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толық экранды ұлғайту"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экранның бөлігін ұлғайту"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Ауысу"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Ұлғайту параметрлерін ашу"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Өлшемін өзгерту үшін бұрышынан сүйреңіз."</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Диагональ бойынша айналдыруға рұқсат беру"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Орташа"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Кішi"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Үлкен"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Дайын"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Өзгерту"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ұлғайтқыш терезесінің параметрлері"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 1106ef2db0a1..c191088a932c 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ប៊ូតុងបិទបើកការពង្រីក"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ពង្រីកពេញអេក្រង់"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ពង្រីកផ្នែកនៃអេក្រង់"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ប៊ូតុងបិទបើក"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"បើកការកំណត់ការពង្រីក"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"អូសជ្រុងដើម្បីប្ដូរទំហំ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"អនុញ្ញាតការរំកិលបញ្ឆិត"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"មធ្យម"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"តូច"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ធំ"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"រួចរាល់"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"កែ"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ការកំណត់វិនដូកម្មវិធីពង្រីក"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index f1c2b9189836..d5d10d9cc011 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ಝೂಮ್ ಮಾಡುವ ಸ್ವಿಚ್"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಹಿಗ್ಗಿಸಿ"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ಸ್ಕ್ರೀನ್ನ ಅರ್ಧಭಾಗವನ್ನು ಝೂಮ್ ಮಾಡಿ"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ಸ್ವಿಚ್"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ಹಿಗ್ಗಿಸುವಿಕೆ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ಮರುಗಾತ್ರಗೊಳಿಸಲು ಮೂಲೆಯನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ಡಯಾಗನಲ್ ಸ್ಕ್ರೋಲಿಂಗ್ ಅನ್ನು ಅನುಮತಿಸಿ"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"ಮಧ್ಯಮ"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"ಚಿಕ್ಕದು"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ದೊಡ್ಡದು"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ಮುಗಿದಿದೆ"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ಎಡಿಟ್ ಮಾಡಿ"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ಮ್ಯಾಗ್ನಿಫೈರ್ ವಿಂಡೋ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index d1f9a2d38476..a62608f82ef7 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"확대 전환"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"전체 화면 확대"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"전환"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"확대 설정 열기"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"모서리를 드래그하여 크기 조절"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"대각선 스크롤 허용"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"보통"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"작게"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"크게"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"완료"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"수정"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"돋보기 창 설정"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 4693950defc8..7f74f3d7b318 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Чоңойтуу режимине которулуу"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толук экранда ачуу"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экрандын бир бөлүгүн чоңойтуу"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Которулуу"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Чоңойтуу параметрлерин ачуу"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Өлчөмүн өзгөртүү үчүн бурчун сүйрөңүз"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Диагональ боюнча сыдырууга уруксат берүү"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Орто"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Кичине"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Чоң"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Бүттү"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Түзөтүү"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Чоңойткуч терезесинин параметрлери"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 21f4312803dc..7646d7e7c82d 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ສະຫຼັບການຂະຫຍາຍ"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ຂະຫຍາຍເຕັມຈໍ"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ຂະຫຍາຍບາງສ່ວນຂອງໜ້າຈໍ"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ສະຫຼັບ"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ເປີດການຕັ້ງຄ່າການຂະຫຍາຍ"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ລາກຢູ່ມຸມເພື່ອປັບຂະໜາດ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ອະນຸຍາດໃຫ້ເລື່ອນທາງຂວາງ"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"ປານກາງ"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"ນ້ອຍ"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ໃຫຍ່"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ແລ້ວໆ"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ແກ້ໄຂ"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ການຕັ້ງຄ່າໜ້າຈໍຂະຫຍາຍ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 326f11b5836f..c74b2ad139a7 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Didinimo jungiklis"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Viso ekrano didinimas"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Didinti ekrano dalį"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Perjungti"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Atidaryti didinimo nustatymus"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Norėdami keisti dydį, vilkite kampą"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Slinkimo įstrižai leidimas"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Vidutinis"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Mažas"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Didelis"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Atlikta"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Redaguoti"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Didinimo lango nustatymai"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index d7e99d43cc78..bba95e1559e5 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Palielinājuma slēdzis"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Palielināt visu ekrānu"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Palielināt ekrāna daļu"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pārslēgt"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Atvērt palielinājuma iestatījumus"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Velciet stūri, lai mainītu izmērus"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Atļaut ritināšanu pa diagonāli"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Vidējs"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Mazs"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Liels"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Gatavs"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Rediģēt"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Lupas loga iestatījumi"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 1948796ac0c9..9625dc37e6da 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Прекинувач за зголемување"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Зголемете го целиот екран"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Зголемувајте дел од екранот"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Префрли"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отвори поставки за зголемување"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Повлечете на аголот за да ја промените големината"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволете дијагонално лизгање"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Средно"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Мало"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Големо"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Готово"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Изменете"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Поставки за прозорец за лупа"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 0a36380d2fee..389539f163cc 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"മാഗ്നിഫിക്കേഷൻ മോഡ് മാറുക"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"സ്ക്രീൻ പൂർണ്ണമായും മാഗ്നിഫൈ ചെയ്യുക"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"സ്ക്രീനിന്റെ ഭാഗം മാഗ്നിഫൈ ചെയ്യുക"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"മാറുക"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"മാഗ്നിഫിക്കേഷൻ ക്രമീകരണം തുറക്കുക"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"വലുപ്പം മാറ്റാൻ മൂല വലിച്ചിടുക"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ഡയഗണൽ സ്ക്രോളിംഗ് അനുവദിക്കുക"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"ഇടത്തരം"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"ചെറുത്"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"വലുത്"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"പൂർത്തിയായി"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"എഡിറ്റ് ചെയ്യുക"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"മാഗ്നിഫയർ വിൻഡോ ക്രമീകരണം"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 759218a5cc50..d85bd33351f9 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Томруулах сэлгэлт"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Бүтэн дэлгэцийг томруулах"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Дэлгэцийн нэг хэсгийг томруулах"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Сэлгэх"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Томруулах тохиргоог нээх"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Хэмжээг өөрчлөхийн тулд булангаас чирнэ үү"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Хөндлөн гүйлгэхийг зөвшөөрнө үү"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Дунд зэрэг"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Жижиг"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Том"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Болсон"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Засах"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Томруулагчийн цонхны тохиргоо"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index c0605a87455d..45088a71682d 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"मॅग्निफिकेशन स्विच"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फुल स्क्रीन मॅग्निफाय करा"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच करा"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"मॅग्निफिकेशन सेटिंग्ज उघडा"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"आकार बदलण्यासाठी कोपरा ड्रॅग करा"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"तिरपे स्क्रोल करण्याची अनुमती द्या"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"मध्यम"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"लहान"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"मोठा"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"पूर्ण झाले"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"संपादित करा"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"मॅग्निफायर विंडो सेटिंग्ज"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index ce9aa402bb8c..769e60650265 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suis pembesaran"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Besarkan skrin penuh"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Besarkan sebahagian skrin"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Tukar"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Buka tetapan pembesaran"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Seret sudut untuk mengubah saiz"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Benarkan penatalan pepenjuru"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Sederhana"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Kecil"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Besar"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Selesai"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Tetapan tetingkap penggadang"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 0194c772c7c6..291e33852f9a 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -124,7 +124,7 @@ <string name="accessibility_back" msgid="6530104400086152611">"နောက်သို့"</string> <string name="accessibility_home" msgid="5430449841237966217">"ပင်မစာမျက်နှာ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"မီနူး"</string> - <string name="accessibility_accessibility_button" msgid="4089042473497107709">"အများသုံးစွဲနိုင်မှု"</string> + <string name="accessibility_accessibility_button" msgid="4089042473497107709">"အများသုံးနိုင်မှု"</string> <string name="accessibility_rotate_button" msgid="1238584767612362586">"မျက်နှာပြင် လှည့်ရန်"</string> <string name="accessibility_recent" msgid="901641734769533575">"ခြုံကြည့်မှု။"</string> <string name="accessibility_camera_button" msgid="2938898391716647247">"ကင်မရာ"</string> @@ -481,13 +481,13 @@ <string name="stream_notification" msgid="7930294049046243939">"အကြောင်းကြားချက်"</string> <string name="stream_bluetooth_sco" msgid="6234562365528664331">"ဘလူးတုသ်"</string> <string name="stream_dtmf" msgid="7322536356554673067">"နှစ်လိုင်းပေါင်း အသံပေါင်းစုံ ကြိမ်နှုန်း"</string> - <string name="stream_accessibility" msgid="3873610336741987152">"အများသုံးစွဲနိုင်မှု"</string> + <string name="stream_accessibility" msgid="3873610336741987152">"အများသုံးနိုင်မှု"</string> <string name="volume_ringer_status_normal" msgid="1339039682222461143">"အသံမြည်သည်"</string> <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"တုန်ခါသည်"</string> <string name="volume_ringer_status_silent" msgid="3691324657849880883">"အသံတိတ်သည်"</string> <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s။ အသံပြန်ဖွင့်ရန် တို့ပါ။"</string> - <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s။ တုန်ခါမှုကို သတ်မှတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string> - <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string> + <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s။ တုန်ခါမှုကို သတ်မှတ်ရန် တို့ပါ။ အများသုံးနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string> + <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string> <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s။ တုန်ခါခြင်းသို့ သတ်မှတ်ရန်တို့ပါ။"</string> <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s။ အသံပိတ်ရန် တို့ပါ။"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ဖုန်းခေါ်သံမုဒ်သို့ ပြောင်းရန် တို့ပါ"</string> @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ချဲ့ရန် ခလုတ်"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ဖန်သားပြင်အပြည့် ချဲ့သည်"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ဖန်သားပြင် တစ်စိတ်တစ်ပိုင်းကို ချဲ့ပါ"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ခလုတ်"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ချဲ့ခြင်း ဆက်တင်များ ဖွင့်ရန်"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"အရွယ်အစားပြန်ပြုပြင်ရန် ထောင့်စွန်းကို ဖိဆွဲပါ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ထောင့်ဖြတ် လှိမ့်ခွင့်ပြုရန်"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"အလတ်"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"အသေး"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"အကြီး"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ပြီးပြီ"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ပြင်ရန်"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"မှန်ဘီလူးဝင်းဒိုး ဆက်တင်များ"</string> @@ -897,7 +898,7 @@ <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"လော့ခ်မျက်နှာပြင်တွင် စက်ပစ္စည်းများ ထိန်းချုပ်မလား။"</string> <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"အချို့စက်များကို ဖုန်း (သို့) တက်ဘလက် လော့ခ်ဖွင့်ရန်မလိုဘဲ ထိန်းချုပ်နိုင်သည်။ ဤနည်းလမ်းအတိုင်း ထိန်းချုပ်နိုင်မည့်စက်များကို သင့်စက်ပစ္စည်းအက်ပ်က ဆုံးဖြတ်သည်။"</string> <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"မလိုပါ"</string> - <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Yes"</string> + <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"လုပ်ပါမည်"</string> <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ပင်နံပါတ်တွင် စာလုံး သို့မဟုတ် သင်္ကေတများပါဝင်သည်"</string> <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ကို အတည်ပြုခြင်း"</string> <string name="controls_pin_wrong" msgid="6162694056042164211">"ပင်နံပါတ် မှားနေသည်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index f0da4e978cc9..23a89c6fa32b 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Forstørringsbryter"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstørr hele skjermen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstørr en del av skjermen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Bytt"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Åpne innstillinger for forstørring"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Dra hjørnet for å endre størrelse"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Tillat diagonal rulling"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Middels"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Liten"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Stor"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Ferdig"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Endre"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Innstillinger for forstørringsvindu"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontroll er lagt til.}other{# kontroller er lagt til.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Fjernet"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vil du legge til <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan velge hvilke kontroller og hvilket innhold som vises her."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vil du fjerne kontrollene for <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favoritt"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favoritt, posisjon <xliff:g id="NUMBER">%d</xliff:g>"</string> @@ -1066,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"redigere"</string> <string name="add" msgid="81036585205287996">"Legg til"</string> <string name="manage_users" msgid="1823875311934643849">"Administrer brukere"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Dette varselet støtter ikke at du drar det til en delt skjerm"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi er utilgjengelig"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteringsmodus"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er stilt inn"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index c45185374fde..7f5943a110d7 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"म्याग्निफिकेसन स्विच"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"पूरै स्क्रिन जुम इन गर्नुहोस्"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रिनको केही भाग म्याग्निफाइ गर्नुहोस्"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"बदल्नुहोस्"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"जुम इनसम्बन्धी सेटिङ खोल्नुहोस्"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"आकार बदल्न कुनाबाट ड्र्याग गर्नुहोस्"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"डायगोनल तरिकाले स्क्रोल गर्ने अनुमति दिनुहोस्"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"मध्यम"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"सानो"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ठुलो"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"सम्पन्न भयो"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"सम्पादन गर्नुहोस्"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"म्याग्निफायर विन्डोसम्बन्धी सेटिङ"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"सम्पादन गर्नुहोस्"</string> <string name="add" msgid="81036585205287996">"हाल्नुहोस्"</string> <string name="manage_users" msgid="1823875311934643849">"प्रयोगकर्ताहरूको व्यवस्थापन गर्नुहोस्"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"यो सूचना ड्र्याग गरेर स्प्लिट स्क्रिनमा लैजान मिल्दैन"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi उपलब्ध छैन"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट गरिएको छ"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 88faab4e97a2..34cde1702f9c 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrotingsschakelaar"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Volledig scherm vergroten"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Deel van het scherm vergroten"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schakelen"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Instellingen voor vergroting openen"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Sleep een hoek om het formaat te wijzigen"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diagonaal scrollen toestaan"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Normaal"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Klein"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Groot"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Klaar"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Bewerken"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Instellingen voor vergrotingsvenster"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index a576ac504b06..328bb376ddbc 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ସ୍ୱିଚ୍"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ମ୍ୟାଗ୍ନିଫାଏ କରନ୍ତୁ"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ସ୍ୱିଚ୍ କରନ୍ତୁ"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ମାଗ୍ନିଫିକେସନ ସେଟିଂସ ଖୋଲନ୍ତୁ"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ରିସାଇଜ କରିବା ପାଇଁ କୋଣକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ଡାଏଗୋନାଲ ସ୍କ୍ରୋଲିଂକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"ମଧ୍ୟମ"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"ଛୋଟ"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ବଡ଼"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ହୋଇଗଲା"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ଏଡିଟ କରନ୍ତୁ"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ମ୍ୟାଗ୍ନିଫାୟର ୱିଣ୍ଡୋର ସେଟିଂସ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index acc9339f4abb..0828b02adea1 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਸਵਿੱਚ"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਨੂੰ ਵੱਡਦਰਸ਼ੀ ਕਰੋ"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ਸਕ੍ਰੀਨ ਦੇ ਹਿੱਸੇ ਨੂੰ ਵੱਡਾ ਕਰੋ"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ਸਵਿੱਚ"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ਆਕਾਰ ਬਦਲਣ ਲਈ ਕੋਨਾ ਘਸੀਟੋ"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"ਟੇਡੀ ਦਿਸ਼ਾ ਵਿੱਚ ਸਕ੍ਰੋਲ ਕਰਨ ਦਿਓ"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"ਦਰਮਿਆਨਾ"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"ਛੋਟਾ"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ਵੱਡਾ"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ਹੋ ਗਿਆ"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ਸੰਪਾਦਨ ਕਰੋ"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ਵੱਡਦਰਸ਼ੀ ਵਿੰਡੋ ਸੈਟਿੰਗਾਂ"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।}one{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।}other{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤੇ ਗਏ।}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ਹਟਾਇਆ ਗਿਆ"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"ਕੀ <xliff:g id="APPNAME">%s</xliff:g> ਸ਼ਾਮਲ ਕਰਨਾ ਹੈ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ਚੁਣ ਸਕਦੀ ਹੈ ਕਿ ਇੱਥੇ ਕਿਹੜੇ ਕੰਟਰੋਲ ਅਤੇ ਕਿਹੜੀ ਸਮੱਗਰੀ ਦਿਸੇਗੀ।"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ਕੀ <xliff:g id="APPNAME">%s</xliff:g> ਲਈ ਕੰਟਰੋਲਾਂ ਨੂੰ ਹਟਾਉਣਾ ਹੈ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ, ਸਥਾਨ <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 078db24b6446..6ce99368d1ef 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Przełączanie powiększenia"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Powiększanie pełnego ekranu"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Powiększ część ekranu"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Przełącz"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otwórz ustawienia powiększenia"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Przeciągnij róg, aby zmienić rozmiar"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Zezwalaj na przewijanie poprzeczne"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Średni"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Mały"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Duży"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Gotowe"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Edytuj"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ustawienia okna powiększania"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"edytować"</string> <string name="add" msgid="81036585205287996">"Dodaj"</string> <string name="manage_users" msgid="1823875311934643849">"Zarządzaj użytkownikami"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"To powiadomienie nie obsługuje dzielenia ekranu przez przeciąganie."</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Sieć Wi‑Fi niedostępna"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tryb priorytetowy"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm ustawiony"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 6b78aa7f3e3f..0d21a5d7ec7d 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Chave de ampliação"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Trocar"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir as configurações de ampliação"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arraste o canto para redimensionar"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir rolagem diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Médio"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeno"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Concluído"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configurações da janela de lupa"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 8595ed0e95f6..8958fdababe0 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor de ampliação"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar o ecrã inteiro"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte do ecrã"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Mudar"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir definições de ampliação"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arrastar o canto para redimensionar"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir deslocamento da página na diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Médio"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeno"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Concluir"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Definições da janela da lupa"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 6b78aa7f3e3f..0d21a5d7ec7d 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Chave de ampliação"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Trocar"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Abrir as configurações de ampliação"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Arraste o canto para redimensionar"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permitir rolagem diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Médio"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Pequeno"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Concluído"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editar"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configurações da janela de lupa"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index c915522ceeba..8c187eb2c37a 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Comutator de mărire"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Mărește tot ecranul"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Mărește o parte a ecranului"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Comutator"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Deschide setările pentru mărire"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Trage de colț pentru a redimensiona"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Permite derularea pe diagonală"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mediu"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Mic"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Mare"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Gata"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Editează"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Setările ferestrei de mărire"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 42fe05662257..f4e364a6f74f 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Переключатель режима увеличения"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличение всего экрана"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличить часть экрана"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Переключить"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Открыть настройки увеличения"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Потяните за угол, чтобы изменить размер"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Разрешить прокручивать по диагонали"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Средняя"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Маленькая"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Большая"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ОК"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Изменить"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Настройка окна лупы"</string> @@ -895,7 +896,7 @@ <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Разрешить показывать устройства и управлять ими на заблокированном экране?"</string> <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Вы можете добавить элементы управления внешними устройствами на заблокированный экран.\n\nПриложение на вашем устройстве может разрешать управление некоторыми устройствами с заблокированного экрана.\n\nИзменить параметры можно в любое время в настройках."</string> <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Управлять устройствами на заблокированном экране?"</string> - <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Некоторыми устройствами можно управлять без разблокировки экрана на телефоне или планшете. Их точный перечень зависит от приложения на вашем устройстве."</string> + <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Некоторыми устройствами можно управлять без разблокировки экрана телефона или планшета. Их список зависит от того, какое у вас сопутствующее приложение."</string> <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Не сейчас"</string> <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Да"</string> <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код содержит буквы или символы"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 5522178ccb5d..c6bc48296db4 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"විශාලන ස්විචය"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"පූර්ණ තිරය විශාලනය කරන්න"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"තිරයේ කොටසක් විශාලනය කරන්න"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ස්විචය"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"විශාලන සැකසීම් විවෘත කරන්න"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ප්රමාණය වෙනස් කිරීමට කොන අදින්න"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"විකර්ණ අනුචලනයට ඉඩ දෙන්න"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"මධ්යම"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"කුඩා"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"විශාල"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"නිමයි"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"සංස්කරණය කරන්න"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"විශාලන කවුළු සැකසීම්"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# පාලනයක් එක් කර ඇත.}one{පාලන #ක් එක් කර ඇත.}other{පාලන #ක් එක් කර ඇත.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ඉවත් කළා"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> එක් කරන්න ද?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> හට මෙහි පෙන්වන්නේ කුමන පාලන සහ අන්තර්ගත ද යන්න තෝරා ගත හැක."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> සඳහා පාලන ඉවත් කරන්න ද?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ප්රියතම කළා"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ප්රියතම කළා, තත්ත්ව <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 72106896d526..49baf94c0a17 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prepínač zväčenia"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zväčšenie celej obrazovky"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zväčšiť časť obrazovky"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prepnúť"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Otvoriť nastavenia zväčšenia"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Veľkosť zmeníte presunutím rohu"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Povoliť diagonálne posúvanie"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Stredný"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Malý"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Veľký"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Hotovo"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Upraviť"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavenia okna lupy"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 7bdb979c3e1c..19ec829b20d9 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Stikalo za povečavo"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povečanje celotnega zaslona"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povečava dela zaslona"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Stikalo"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Odpri nastavitve povečave"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Povlecite vogal, da spremenite velikost."</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Dovoli diagonalno pomikanje"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednja"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Majhna"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Velika"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Končano"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Uredi"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavitve okna povečevalnika"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 71da15c73614..2bbad3b2a9f2 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Ndërrimi i zmadhimit"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zmadho ekranin e plotë"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zmadho një pjesë të ekranit"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Ndërro"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Hap cilësimet e zmadhimit"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Zvarrit këndin për të ndryshuar përmasat"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Lejo lëvizjen diagonale"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Mesatar"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"I vogël"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"I madh"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"U krye"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Modifiko"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Cilësimet e dritares së zmadhimit"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 6136c367702a..0108b0da0dfc 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Прелазак на други режим увећања"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увећајте цео екран"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увећајте део екрана"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Пређи"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Отвори подешавања увећања"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Превуците угао да бисте променили величину"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволи дијагонално скроловање"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Средње"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Мало"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Велико"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Готово"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Измени"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Подешавања прозора за увећање"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index f359ae90cfda..83dd3bf4f5ed 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Förstoringsreglage"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Förstora hela skärmen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Förstora en del av skärmen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Reglage"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Öppna inställningarna för förstoring"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Dra i hörnet för att ändra storlek"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Tillåt diagonal scrollning"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Medel"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Liten"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Stor"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Klar"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Redigera"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Inställningar för förstoringsfönster"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 6973c89d8bb2..88d0e53620b7 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Swichi ya ukuzaji"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Kuza skrini nzima"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Kuza sehemu ya skrini"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Swichi"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Fungua mipangilio ya ukuzaji"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Buruta kona ili ubadilishe ukubwa"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Ruhusu usogezaji wa kimshazari"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Wastani"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Ndogo"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Kubwa"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Nimemaliza"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Badilisha"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Mipangilio ya dirisha la kikuzaji"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"ubadilishe"</string> <string name="add" msgid="81036585205287996">"Weka"</string> <string name="manage_users" msgid="1823875311934643849">"Dhibiti watumiaji"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Arifa hii haitumii utaratibu wa kuburuta ili kugawa skrini"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi haipatikani"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Hali ya kipaumbele"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Kengele imewekwa"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index e32f28ad8265..fe8d2cf8a320 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"பெரிதாக்கல் ஸ்விட்ச்"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"முழுத்திரையைப் பெரிதாக்கும்"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"திரையின் ஒரு பகுதியைப் பெரிதாக்கும்"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ஸ்விட்ச்"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"பெரிதாக்கல் அமைப்புகளைத் திற"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"அளவை மாற்ற மூலையை இழுக்கவும்"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"குறுக்கே ஸ்க்ரோல் செய்வதை அனுமதி"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"நடுத்தரமானது"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"சிறியது"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"பெரியது"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"முடிந்தது"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"மாற்று"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"சாளரத்தைப் பெரிதாக்கும் கருவிக்கான அமைப்புகள்"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# கட்டுப்பாடு சேர்க்கப்பட்டது.}other{# கட்டுப்பாடுகள் சேர்க்கப்பட்டன.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"அகற்றப்பட்டது"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ஆப்ஸைச் சேர்க்கவா?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"இங்கே எந்தெந்தக் கட்டுப்பாடுகளும் உள்ளடக்கமும் காட்டப்பட வேண்டும் என்பதை <xliff:g id="APPNAME">%s</xliff:g> ஆப்ஸால் தேர்வுசெய்ய முடியும்."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> ஆப்ஸுக்கான கட்டுப்பாடுகளை அகற்றவா?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"பிடித்தவற்றில் சேர்க்கப்பட்டது"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"பிடித்தவற்றில் சேர்க்கப்பட்டது, நிலை <xliff:g id="NUMBER">%d</xliff:g>"</string> @@ -1066,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"திருத்தும்"</string> <string name="add" msgid="81036585205287996">"சேர்"</string> <string name="manage_users" msgid="1823875311934643849">"பயனர்களை நிர்வகித்தல்"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"பிரிக்கப்பட்ட திரைக்குள் இந்த அறிவிப்பை இழுத்துவிட முடியாது"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"வைஃபை கிடைக்கவில்லை"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"முன்னுரிமைப் பயன்முறை"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"அலாரம் அமைக்கப்பட்டுள்ளது"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 894298a224be..a9760fabb4c2 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -682,8 +682,8 @@ <string-array name="nav_bar_layouts"> <item msgid="9156773083127904112">"సాధారణం"</item> <item msgid="2019571224156857610">"సంక్షిప్తమైనది"</item> - <item msgid="7453955063378349599">"ఎడమవైపుకు వాలుగా"</item> - <item msgid="5874146774389433072">"కుడివైపుకు వాలుగా"</item> + <item msgid="7453955063378349599">"ఎడమ వైపునకు వాలుగా"</item> + <item msgid="5874146774389433072">"కుడి వైపునకు వాలుగా"</item> </string-array> <string name="save" msgid="3392754183673848006">"సేవ్ చేయండి"</string> <string name="reset" msgid="8715144064608810383">"రీసెట్ చేయండి"</string> @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"మ్యాగ్నిఫికేషన్ స్విచ్"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ఫుల్ స్క్రీన్ను మ్యాగ్నిఫై చేయండి"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్లో భాగాన్ని మ్యాగ్నిఫై చేయండి"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"స్విచ్ చేయి"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"మ్యాగ్నిఫికేషన్ సెట్టింగ్లను తెరవండి"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"సైజ్ మార్చడానికి మూలను లాగండి"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"వికర్ణ స్క్రోలింగ్ను అనుమతించండి"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"మధ్యస్థం"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"చిన్నది"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"పెద్దది"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"పూర్తయింది"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ఎడిట్ చేయండి"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"మాగ్నిఫయర్ విండో సెట్టింగ్లు"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index d1414024f236..769f7d82ca7c 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"เปลี่ยนโหมดการขยาย"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ขยายเป็นเต็มหน้าจอ"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ขยายบางส่วนของหน้าจอ"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"เปลี่ยน"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"เปิดการตั้งค่าการขยาย"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"ลากที่มุมเพื่อปรับขนาด"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"อนุญาตการเลื่อนแบบทแยงมุม"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"ปานกลาง"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"เล็ก"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"ใหญ่"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"เสร็จสิ้น"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"แก้ไข"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"การตั้งค่าหน้าต่างแว่นขยาย"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 732094fd1646..7cdd6dcd35b8 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Switch ng pag-magnify"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"I-magnify ang buong screen"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"I-magnify ang isang bahagi ng screen"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Buksan ang mga setting ng pag-magnify"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"I-drag ang sulok para i-resize"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Payagan ang diagonal na pag-scroll"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Katamtaman"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Maliit"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Malaki"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Tapos na"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"I-edit"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Mga setting ng window ng magnifier"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 3c3c0799d1c2..cdfea9005e2a 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Büyütme moduna geçin"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekran büyütme"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekranın bir parçasını büyütün"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Geç"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Büyütme ayarlarını aç"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Yeniden boyutlandırmak için köşeyi sürükleyin"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Çapraz kaydırmaya izin ver"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Orta"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Küçük"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Büyük"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Bitti"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Düzenle"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Büyüteç penceresi ayarları"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrol eklendi.}other{# kontrol eklendi.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Kaldırıldı"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> eklensin mi?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> uygulaması hangi kontrollerin ve içeriklerin burada gösterileceğini seçebilir."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> için denetimler kaldırılsın mı?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favoriler listesine eklendi"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorilere eklendi, konum: <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index eecabf4bd0c1..4ad9649ce9a0 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Перемикач режиму збільшення"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Збільшення всього екрана"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Збільшити частину екрана"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Перемкнути"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Відкрити налаштування збільшення"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Потягніть кут, щоб змінити розмір"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Дозволити прокручування по діагоналі"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Звичайна"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Мала"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Велика"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Готово"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Змінити"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Налаштування розміру лупи"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Додано # елемент керування.}one{Додано # елемент керування.}few{Додано # елементи керування.}many{Додано # елементів керування.}other{Додано # елемента керування.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Вилучено"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Долучити додаток <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"У додатку <xliff:g id="APPNAME">%s</xliff:g> можна вибрати, які елементи керування і контент тут відображатимуться."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Вилучити елементи керування для додатка <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Додано у вибране"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Додано у вибране, позиція <xliff:g id="NUMBER">%d</xliff:g>"</string> @@ -1066,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"змінити"</string> <string name="add" msgid="81036585205287996">"Додати"</string> <string name="manage_users" msgid="1823875311934643849">"Керувати користувачами"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"Це сповіщення не підтримує режим розділеного екрана"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Мережа Wi-Fi недоступна"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Режим пріоритету"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлено"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 89e6930bb3d9..d601e8fcc462 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"میگنیفکیشن پر سوئچ کریں"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"فُل اسکرین کو بڑا کریں"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"اسکرین کا حصہ بڑا کریں"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"سوئچ کریں"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"میگنیفکیشن کی ترتیبات کھولیں"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"سائز تبدیل کرنے کے لیے کونے کو گھسیٹیں"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"وتری سکرولنگ کی اجازت دیں"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"متوسط"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"چھوٹا"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"بڑا"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"ہو گیا"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"ترمیم کریں"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"میگنیفائر ونڈو کی ترتیبات"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index a701ae353b51..b005ebcdbe2d 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Kattalashtirish rejimini almashtirish"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ekranni toʻliq kattalashtirish"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran qismini kattalashtirish"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Almashtirish"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Kattalashtirish sozlamalarini ochish"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Oʻlchamini oʻzgartirish uchun burchakni torting"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Diagonal aylantirishga ruxsat berish"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Oʻrtacha"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Kichik"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Yirik"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Tayyor"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Tahrirlash"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Lupa oynasi sozlamalari"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 8f651b0ea5d1..5ebf5cd9cdbe 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Nút chuyển phóng to"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Phóng to toàn màn hình"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Phóng to một phần màn hình"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Chuyển"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Mở chế độ cài đặt phóng to"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Kéo góc để thay đổi kích thước"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Cho phép cuộn chéo"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Vừa"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Nhỏ"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Lớn"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Xong"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Chỉnh sửa"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Chế độ cài đặt cửa sổ phóng to"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 5532c296c8ea..58217aed2407 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"切换放大模式"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整个屏幕"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分屏幕"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切换"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"打开放大功能设置"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"拖动一角即可调整大小"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允许沿对角线滚动"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"中"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"小"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"大"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"完成"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"修改"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大镜窗口设置"</string> @@ -894,7 +895,7 @@ <string name="controls_tile_locked" msgid="731547768182831938">"设备已锁定"</string> <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"要从锁定屏幕上显示和控制设备吗?"</string> <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"您可以在锁定屏幕上添加用于控制外部设备的控件。\n\n您的设备应用可能会允许您在不解锁手机或平板电脑的情况下控制某些设备。\n\n您可以随时在“设置”中进行更改。"</string> - <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"要从锁定屏幕上控制设备吗?"</string> + <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"要在锁屏状态下控制设备吗?"</string> <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"您可以在不解锁手机或平板电脑的情况下控制某些设备。您的设备配套应用将决定哪些设备可以通过这种方式进行控制。"</string> <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"不用了"</string> <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"是"</string> @@ -1065,8 +1066,7 @@ <string name="clipboard_edit" msgid="4500155216174011640">"修改"</string> <string name="add" msgid="81036585205287996">"添加"</string> <string name="manage_users" msgid="1823875311934643849">"管理用户"</string> - <!-- no translation found for drag_split_not_supported (7173481676120546121) --> - <skip /> + <string name="drag_split_not_supported" msgid="7173481676120546121">"此通知不支持拖动到分屏中"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN 已关闭"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"优先模式"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"闹钟已设置"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index e6ece129b266..77e8e5df1701 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"放大開關"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大成個畫面"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分螢幕畫面"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切換"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"開啟放大設定"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"拖曳角落即可調整大小"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允許斜角捲動"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"中"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"小"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"大"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"完成"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"編輯"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大鏡視窗設定"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已新增 # 個控制項。}other{已新增 # 個控制項。}}"</string> <string name="controls_removed" msgid="3731789252222856959">"已移除"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"要新增「<xliff:g id="APPNAME">%s</xliff:g>」嗎?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"「<xliff:g id="APPNAME">%s</xliff:g>」可選擇要在這裡顯示的控制項和內容。"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"要移除「<xliff:g id="APPNAME">%s</xliff:g>」的控制項嗎?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"已加入收藏"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"已加入至收藏位置 <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 7af44dc02397..ef64b8d8eec1 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"切換放大模式"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整個螢幕畫面"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大局部螢幕畫面"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切換"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"開啟放大功能設定"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"拖曳角落即可調整大小"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"允許沿對角線捲動"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"中"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"小"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"大"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"完成"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"編輯"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大鏡視窗設定"</string> @@ -870,8 +871,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已新增 # 個控制項。}other{已新增 # 個控制項。}}"</string> <string name="controls_removed" msgid="3731789252222856959">"已移除"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"要新增「<xliff:g id="APPNAME">%s</xliff:g>」嗎?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"「<xliff:g id="APPNAME">%s</xliff:g>」可選擇要顯示在這裡的控制選項和內容。"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"要移除「<xliff:g id="APPNAME">%s</xliff:g>」的控制嗎?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"已加入收藏"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"已加入收藏,位置 <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 5a2af599ae6d..f658544f6440 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -832,7 +832,6 @@ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Iswishi yokukhulisa"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Khulisa isikrini esigcwele"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Khulisa ingxenye eyesikrini"</string> - <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Iswishi"</string> <string name="magnification_open_settings_click_label" msgid="6151849212725923363">"Vula amasethingi okukhuliswa"</string> <string name="magnification_drag_corner_to_resize" msgid="1249766311052418130">"Hudula ikhona ukuze usayize kabusha"</string> <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Vumela ukuskrola oku-diagonal"</string> @@ -849,6 +848,8 @@ <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Kumaphakathi"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Esincane"</string> <string name="accessibility_magnification_large" msgid="6602944330021308774">"Obukhulu"</string> + <!-- no translation found for accessibility_magnification_fullscreen (5043514702759201964) --> + <skip /> <string name="accessibility_magnification_done" msgid="263349129937348512">"Kwenziwe"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Hlela"</string> <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Amasethingi ewindi lesikhulisi"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 249fc8664c7e..2663ffb1fed9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -793,6 +793,7 @@ <dimen name="keyguard_affordance_fixed_height">48dp</dimen> <dimen name="keyguard_affordance_fixed_width">48dp</dimen> <dimen name="keyguard_affordance_fixed_radius">24dp</dimen> + <dimen name="keyguard_affordance_fixed_padding">12dp</dimen> <!-- Amount the button should shake when it's not long-pressed for long enough. --> <dimen name="keyguard_affordance_shake_amplitude">8dp</dimen> @@ -1406,13 +1407,13 @@ <dimen name="pulse_expansion_max_top_overshoot">32dp</dimen> <!-- The drag amount required for the split shade to fully expand. --> - <dimen name="split_shade_full_transition_distance">200dp</dimen> + <dimen name="split_shade_full_transition_distance">400dp</dimen> <!-- The drag amount required for the scrim to fully fade in when expanding the split shade. Currently setting it a little longer than the full shade transition distance, to avoid having a state where the screen is fully black without any content showing. --> - <dimen name="split_shade_scrim_transition_distance">300dp</dimen> + <dimen name="split_shade_scrim_transition_distance">600dp</dimen> <dimen name="people_space_widget_radius">28dp</dimen> <dimen name="people_space_image_radius">20dp</dimen> @@ -1552,6 +1553,9 @@ <dimen name="status_bar_user_chip_end_margin">12dp</dimen> <dimen name="status_bar_user_chip_text_size">12sp</dimen> + <!-- System UI Dialog --> + <dimen name="dialog_title_text_size">24sp</dimen> + <!-- Internet panel related dimensions --> <dimen name="internet_dialog_list_max_height">662dp</dimen> <!-- The height of the WiFi network in Internet panel. --> diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index 8d4431520c75..befbfab7dbc3 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -37,4 +37,12 @@ <dimen name="percent_displacement_at_fade_out" format="float">0.1066</dimen> <integer name="qs_carrier_max_em">7</integer> + + <!-- Maximum number of notification icons shown on the Always on Display + (excluding overflow dot) --> + <integer name="max_notif_icons_on_aod">3</integer> + <!-- Maximum number of notification icons shown on the lockscreen (excluding overflow dot) --> + <integer name="max_notif_icons_on_lockscreen">3</integer> + <!-- Maximum number of notification icons shown in the status bar (excluding overflow dot) --> + <integer name="max_notif_static_icons">4</integer> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index e7be6fc80d1c..324ba02a7a46 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1270,6 +1270,11 @@ <!-- Label for button to go to sound settings screen [CHAR_LIMIT=30] --> <string name="volume_panel_dialog_settings_button">Settings</string> + <!-- Title for notification after audio lowers --> + <string name="csd_lowered_title" product="default">Lowered to safer volume</string> + <!-- Message shown in notification after system lowers audio --> + <string name="csd_system_lowered_text" product="default">The volume has been high for longer than recommended</string> + <!-- content description for audio output chooser [CHAR LIMIT=NONE]--> <!-- Screen pinning dialog title. --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 2fb1592dfe15..8a86fd560655 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -844,12 +844,10 @@ <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> </style> - <style name="Theme.UserSwitcherActivity" parent="@android:style/Theme.DeviceDefault.NoActionBar"> + <style name="Theme.UserSwitcherFullscreenDialog" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"> <item name="android:statusBarColor">@color/user_switcher_fullscreen_bg</item> <item name="android:windowBackground">@color/user_switcher_fullscreen_bg</item> <item name="android:navigationBarColor">@color/user_switcher_fullscreen_bg</item> - <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen --> - <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item> </style> <style name="Theme.CreateUser" parent="@android:style/Theme.DeviceDefault.NoActionBar"> @@ -1043,7 +1041,7 @@ <style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large"> <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:textSize">24sp</item> + <item name="android:textSize">@dimen/dialog_title_text_size</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:lineHeight">32sp</item> <item name="android:gravity">center</item> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index f8cb38d7488b..9f2333d8f435 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -277,6 +277,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey @Override public void onResume(int reason) { mResumed = true; + reset(); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index a010c9a16517..d221e22a4fcd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -26,7 +26,6 @@ import android.text.method.TextKeyListener; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; -import android.view.WindowInsets; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -157,15 +156,6 @@ public class KeyguardPasswordViewController // TODO: Remove this workaround by ensuring such a race condition never happens. mMainExecutor.executeDelayed( this::updateSwitchImeButton, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON); - mView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { - @Override - public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { - if (!mKeyguardViewController.isBouncerShowing()) { - mView.hideKeyboard(); - } - return insets; - } - }); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 0c1748982e51..68b40ab233f6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -271,6 +271,12 @@ public class KeyguardPatternViewController } @Override + public void onResume(int reason) { + super.onResume(reason); + reset(); + } + + @Override public void onPause() { super.onPause(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java index fd47e39534a7..f23bb0ae11f6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -38,12 +38,15 @@ public class KeyguardPinViewController private LockPatternUtils mLockPatternUtils; private final FeatureFlags mFeatureFlags; private static final int DEFAULT_PIN_LENGTH = 6; + private static final int MIN_FAILED_PIN_ATTEMPTS = 5; private NumPadButton mBackspaceKey; private View mOkButton = mView.findViewById(R.id.key_enter); private int mUserId; private long mPinLength; + private int mPasswordFailedAttempts; + protected KeyguardPinViewController(KeyguardPINView view, KeyguardUpdateMonitor keyguardUpdateMonitor, SecurityMode securityMode, LockPatternUtils lockPatternUtils, @@ -82,8 +85,10 @@ public class KeyguardPinViewController protected void onUserInput() { super.onUserInput(); if (isAutoConfirmation()) { + updateOKButtonVisibility(); updateBackSpaceVisibility(); - if (mPasswordEntry.getText().length() == mPinLength) { + if (mPasswordEntry.getText().length() == mPinLength + && mOkButton.getVisibility() == View.INVISIBLE) { verifyPasswordAndUnlock(); } } @@ -101,7 +106,7 @@ public class KeyguardPinViewController mUserId = KeyguardUpdateMonitor.getCurrentUser(); mPinLength = mLockPatternUtils.getPinLength(mUserId); mBackspaceKey.setTransparentMode(/* isTransparentMode= */ isAutoConfirmation()); - mOkButton.setVisibility(isAutoConfirmation() ? View.INVISIBLE : View.VISIBLE); + updateOKButtonVisibility(); updateBackSpaceVisibility(); mPasswordEntry.setUsePinShapes(true); mPasswordEntry.setIsPinHinting(isAutoConfirmation() && isPinHinting()); @@ -115,7 +120,18 @@ public class KeyguardPinViewController mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable); } - // + + /** + * Updates the visibility of the OK button for auto confirm feature + */ + private void updateOKButtonVisibility() { + mPasswordFailedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(mUserId); + if (isAutoConfirmation() && mPasswordFailedAttempts < MIN_FAILED_PIN_ATTEMPTS) { + mOkButton.setVisibility(View.INVISIBLE); + } else { + mOkButton.setVisibility(View.VISIBLE); + } + } /** * Updates the visibility and the enabled state of the backspace. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 1a572b729a6e..67874e13298c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -753,7 +753,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard case SimPuk: // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); - if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled( + if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled( KeyguardUpdateMonitor.getCurrentUser())) { finish = true; eventSubtype = BOUNCER_DISMISS_SIM; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java index 68e1dd7d8eab..ddf11997d3a7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java @@ -54,19 +54,23 @@ public class KeyguardSecurityViewFlipperController private final Factory mKeyguardSecurityViewControllerFactory; private final FeatureFlags mFeatureFlags; + private final ViewMediatorCallback mViewMediatorCallback; + @Inject protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, LayoutInflater layoutInflater, AsyncLayoutInflater asyncLayoutInflater, KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory, EmergencyButtonController.Factory emergencyButtonControllerFactory, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + ViewMediatorCallback viewMediatorCallback) { super(view); mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; mLayoutInflater = layoutInflater; mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; mAsyncLayoutInflater = asyncLayoutInflater; mFeatureFlags = featureFlags; + mViewMediatorCallback = viewMediatorCallback; } @Override @@ -152,6 +156,7 @@ public class KeyguardSecurityViewFlipperController keyguardSecurityCallback); childController.init(); mChildren.add(childController); + mViewMediatorCallback.setNeedsInput(childController.needsInput()); if (onViewInflatedListener != null) { onViewInflatedListener.onViewInflated(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 1de3ddd7c1dd..e1bca89091b2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -99,11 +99,13 @@ import android.hardware.biometrics.SensorProperties; import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.usb.UsbManager; import android.nfc.NfcAdapter; import android.os.CancellationSignal; @@ -172,6 +174,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -1899,8 +1902,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab CancellationSignal mFingerprintCancelSignal; @VisibleForTesting CancellationSignal mFaceCancelSignal; - private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; - private List<FaceSensorPropertiesInternal> mFaceSensorProperties; + private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties = + Collections.emptyList(); + private List<FaceSensorPropertiesInternal> mFaceSensorProperties = Collections.emptyList(); private boolean mFingerprintLockedOut; private boolean mFingerprintLockedOutPermanent; private boolean mFaceLockedOutPermanent; @@ -2366,11 +2370,29 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab setStrongAuthTracker(mStrongAuthTracker); if (mFpm != null) { - mFingerprintSensorProperties = mFpm.getSensorPropertiesInternal(); + mFpm.addAuthenticatorsRegisteredCallback( + new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FingerprintSensorPropertiesInternal> sensors) + throws RemoteException { + mFingerprintSensorProperties = sensors; + updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); + mLogger.d("FingerprintManager onAllAuthenticatorsRegistered"); + } + }); mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback); } if (mFaceManager != null) { - mFaceSensorProperties = mFaceManager.getSensorPropertiesInternal(); + mFaceManager.addAuthenticatorsRegisteredCallback( + new IFaceAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + List<FaceSensorPropertiesInternal> sensors) throws RemoteException { + mFaceSensorProperties = sensors; + mLogger.d("FaceManager onAllAuthenticatorsRegistered"); + } + }); mFaceManager.addLockoutResetCallback(mFaceLockoutResetCallback); } @@ -2476,8 +2498,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered. */ public boolean isUdfpsSupported() { - return mAuthController.getUdfpsProps() != null - && !mAuthController.getUdfpsProps().isEmpty(); + return mAuthController.isUdfpsSupported(); } /** @@ -2492,8 +2513,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered. */ public boolean isSfpsSupported() { - return mAuthController.getSfpsProps() != null - && !mAuthController.getSfpsProps().isEmpty(); + return mAuthController.isSfpsSupported(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 64a9cc995248..2503520ba1d9 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -17,7 +17,6 @@ package com.android.systemui; import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_X; -import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_Y; import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat; import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS; @@ -92,7 +91,6 @@ public class SwipeHelper implements Gefingerpoken { private float mTouchSlopMultiplier; private final Callback mCallback; - private final int mSwipeDirection; private final VelocityTracker mVelocityTracker; private final FalsingManager mFalsingManager; private final FeatureFlags mFeatureFlags; @@ -141,12 +139,10 @@ public class SwipeHelper implements Gefingerpoken { private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>(); public SwipeHelper( - int swipeDirection, Callback callback, Resources resources, - ViewConfiguration viewConfiguration, FalsingManager falsingManager, - FeatureFlags featureFlags) { + Callback callback, Resources resources, ViewConfiguration viewConfiguration, + FalsingManager falsingManager, FeatureFlags featureFlags) { mCallback = callback; mHandler = new Handler(); - mSwipeDirection = swipeDirection; mVelocityTracker = VelocityTracker.obtain(); mPagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop(); mSlopMultiplier = viewConfiguration.getScaledAmbiguousGestureMultiplier(); @@ -179,22 +175,22 @@ public class SwipeHelper implements Gefingerpoken { } private float getPos(MotionEvent ev) { - return mSwipeDirection == X ? ev.getX() : ev.getY(); + return ev.getX(); } private float getPerpendicularPos(MotionEvent ev) { - return mSwipeDirection == X ? ev.getY() : ev.getX(); + return ev.getY(); } protected float getTranslation(View v) { - return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY(); + return v.getTranslationX(); } private float getVelocity(VelocityTracker vt) { - return mSwipeDirection == X ? vt.getXVelocity() : - vt.getYVelocity(); + return vt.getXVelocity(); } + protected Animator getViewTranslationAnimator(View view, float target, AnimatorUpdateListener listener) { @@ -209,8 +205,7 @@ public class SwipeHelper implements Gefingerpoken { protected Animator createTranslationAnimation(View view, float newPos, AnimatorUpdateListener listener) { - ObjectAnimator anim = ObjectAnimator.ofFloat(view, - mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos); + ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, newPos); if (listener != null) { anim.addUpdateListener(listener); @@ -220,18 +215,13 @@ public class SwipeHelper implements Gefingerpoken { } protected void setTranslation(View v, float translate) { - if (v == null) { - return; - } - if (mSwipeDirection == X) { + if (v != null) { v.setTranslationX(translate); - } else { - v.setTranslationY(translate); } } protected float getSize(View v) { - return mSwipeDirection == X ? v.getMeasuredWidth() : v.getMeasuredHeight(); + return v.getMeasuredWidth(); } public void setMinSwipeProgress(float minSwipeProgress) { @@ -426,15 +416,12 @@ public class SwipeHelper implements Gefingerpoken { float newPos; boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - // if we use the Menu to dismiss an item in landscape, animate up - boolean animateUpForMenu = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll) - && mSwipeDirection == Y; // if the language is rtl we prefer swiping to the left boolean animateLeftForRtl = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll) && isLayoutRtl; boolean animateLeft = (Math.abs(velocity) > getEscapeVelocity() && velocity < 0) || (getTranslation(animView) < 0 && !isDismissAll); - if (animateLeft || animateLeftForRtl || animateUpForMenu) { + if (animateLeft || animateLeftForRtl) { newPos = -getTotalTranslationLength(animView); } else { newPos = getTotalTranslationLength(animView); @@ -576,8 +563,7 @@ public class SwipeHelper implements Gefingerpoken { startVelocity, mSnapBackSpringConfig); } - return PhysicsAnimator.getInstance(target).spring( - mSwipeDirection == X ? TRANSLATION_X : TRANSLATION_Y, toPosition, startVelocity, + return PhysicsAnimator.getInstance(target).spring(TRANSLATION_X, toPosition, startVelocity, mSnapBackSpringConfig); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt index 1836ce857783..c9579d5e1356 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt @@ -21,6 +21,7 @@ import android.content.pm.ActivityInfo import android.content.res.Configuration import android.os.Bundle import android.provider.Settings +import android.util.TypedValue import android.view.LayoutInflater import android.widget.Button import android.widget.SeekBar @@ -49,8 +50,7 @@ class FontScalingDialog( private lateinit var seekBarWithIconButtonsView: SeekBarWithIconButtonsView private var lastProgress: Int = -1 - private val configuration: Configuration = - Configuration(context.getResources().getConfiguration()) + private val configuration: Configuration = Configuration(context.resources.configuration) override fun onCreate(savedInstanceState: Bundle?) { setTitle(R.string.font_scaling_dialog_title) @@ -84,31 +84,45 @@ class FontScalingDialog( seekBarWithIconButtonsView.setOnSeekBarChangeListener( object : OnSeekBarChangeListener { - override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { - if (progress != lastProgress) { - if (!fontSizeHasBeenChangedFromTile) { - backgroundExecutor.execute { updateSecureSettingsIfNeeded() } - fontSizeHasBeenChangedFromTile = true - } - - backgroundExecutor.execute { updateFontScale(strEntryValues[progress]) } + var isTrackingTouch = false - lastProgress = progress + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { + if (!isTrackingTouch) { + // The seekbar progress is changed by icon buttons + changeFontSize(progress) + } else { + // Provide preview configuration for text instead of changing the system + // font scale before users release their finger from the seekbar. + createTextPreview(progress) } } override fun onStartTrackingTouch(seekBar: SeekBar) { - // Do nothing + isTrackingTouch = true } override fun onStopTrackingTouch(seekBar: SeekBar) { - // Do nothing + isTrackingTouch = false + changeFontSize(seekBar.progress) } } ) doneButton.setOnClickListener { dismiss() } } + private fun changeFontSize(progress: Int) { + if (progress != lastProgress) { + if (!fontSizeHasBeenChangedFromTile) { + backgroundExecutor.execute { updateSecureSettingsIfNeeded() } + fontSizeHasBeenChangedFromTile = true + } + + backgroundExecutor.execute { updateFontScale(strEntryValues[progress]) } + + lastProgress = progress + } + } + private fun fontSizeValueToIndex(value: Float): Int { var lastValue = strEntryValues[0].toFloat() for (i in 1 until strEntryValues.size) { @@ -153,6 +167,20 @@ class FontScalingDialog( } } + /** Provides font size preview for text before putting the final settings to the system. */ + fun createTextPreview(index: Int) { + val previewConfig = Configuration(configuration) + previewConfig.fontScale = strEntryValues[index].toFloat() + + val previewConfigContext = context.createConfigurationContext(previewConfig) + previewConfigContext.theme.setTo(context.theme) + + title.setTextSize( + TypedValue.COMPLEX_UNIT_PX, + previewConfigContext.resources.getDimension(R.dimen.dialog_title_text_size) + ) + } + companion object { private const val ON = "1" private const val OFF = "0" diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 705fc8c1a8fd..92344dbbfe15 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -984,6 +984,36 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, return mSidefpsProps; } + /** + * @return true if udfps HW is supported on this device. Can return true even if the user has + * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered. + */ + public boolean isUdfpsSupported() { + return getUdfpsProps() != null && !getUdfpsProps().isEmpty(); + } + + /** + * @return true if sfps HW is supported on this device. Can return true even if the user has + * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered. + */ + public boolean isSfpsSupported() { + return getSfpsProps() != null && !getSfpsProps().isEmpty(); + } + + /** + * @return true if rear fps HW is supported on this device. Can return true even if the user has + * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered. + */ + public boolean isRearFpsSupported() { + for (FingerprintSensorPropertiesInternal prop: mFpProps) { + if (prop.sensorType == TYPE_REAR) { + return true; + } + } + return false; + } + + private String getErrorString(@Modality int modality, int error, int vendorCode) { switch (modality) { case TYPE_FACE: diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt index c98a62f36656..eb5d23a23abb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt @@ -59,8 +59,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.DelayableExecutor @@ -90,7 +88,6 @@ constructor( @Main private val handler: Handler, private val alternateBouncerInteractor: AlternateBouncerInteractor, @Application private val scope: CoroutineScope, - private val featureFlags: FeatureFlags, dumpManager: DumpManager ) : Dumpable { private val requests: HashSet<SideFpsUiRequestSource> = HashSet() @@ -191,14 +188,12 @@ constructor( private fun listenForAlternateBouncerVisibility() { alternateBouncerInteractor.setAlternateBouncerUIAvailable(true) - if (featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER)) { - scope.launch { - alternateBouncerInteractor.isVisible.collect { isVisible: Boolean -> - if (isVisible) { - show(SideFpsUiRequestSource.ALTERNATE_BOUNCER, REASON_AUTH_KEYGUARD) - } else { - hide(SideFpsUiRequestSource.ALTERNATE_BOUNCER) - } + scope.launch { + alternateBouncerInteractor.isVisible.collect { isVisible: Boolean -> + if (isVisible) { + show(SideFpsUiRequestSource.ALTERNATE_BOUNCER, REASON_AUTH_KEYGUARD) + } else { + hide(SideFpsUiRequestSource.ALTERNATE_BOUNCER) } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java index ee9081c7027d..178cda46cdda 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java @@ -24,6 +24,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; +import android.content.res.ColorStateList; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; @@ -176,7 +177,9 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary); - mBgProtection.setImageDrawable(getContext().getDrawable(R.drawable.fingerprint_bg)); + final int backgroundColor = Utils.getColorAttrDefaultColor(getContext(), + com.android.internal.R.attr.colorSurface); + mBgProtection.setImageTintList(ColorStateList.valueOf(backgroundColor)); mLockScreenFp.invalidate(); // updated with a valueCallback } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt index 231e7a429c53..3e7d81a9de90 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt @@ -42,7 +42,6 @@ import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.KeyguardViewManagerCallback -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.OccludingAppBiometricUI import com.android.systemui.statusbar.phone.SystemUIDialogManager import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController @@ -82,8 +81,6 @@ constructor( ) { private val useExpandedOverlay: Boolean = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION) - private val isModernAlternateBouncerEnabled: Boolean = - featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER) private var showingUdfpsBouncer = false private var udfpsRequested = false private var qsExpansion = 0f @@ -107,7 +104,7 @@ constructor( ) } } - private var inputBouncerExpansion = 0f // only used for modernBouncer + private var inputBouncerExpansion = 0f private val stateListener: StatusBarStateController.StateListener = object : StatusBarStateController.StateListener { @@ -251,7 +248,7 @@ constructor( // that may make the view visible again. repeatOnLifecycle(Lifecycle.State.CREATED) { listenForBouncerExpansion(this) - if (isModernAlternateBouncerEnabled) listenForAlternateBouncerVisibility(this) + listenForAlternateBouncerVisibility(this) } } } @@ -295,7 +292,6 @@ constructor( view.updatePadding() updateAlpha() updatePauseAuth() - keyguardViewManager.setLegacyAlternateBouncer(legacyAlternateBouncer) keyguardViewManager.setOccludingAppBiometricUI(occludingAppBiometricUI) lockScreenShadeTransitionController.udfpsKeyguardViewController = this activityLaunchAnimator.addListener(activityLaunchAnimatorListener) @@ -309,7 +305,6 @@ constructor( faceDetectRunning = false keyguardStateController.removeCallback(keyguardStateControllerCallback) statusBarStateController.removeCallback(stateListener) - keyguardViewManager.removeLegacyAlternateBouncer(legacyAlternateBouncer) keyguardViewManager.removeOccludingAppBiometricUI(occludingAppBiometricUI) keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false) configurationController.removeCallback(configurationListener) @@ -323,7 +318,6 @@ constructor( override fun dump(pw: PrintWriter, args: Array<String>) { super.dump(pw, args) - pw.println("isModernAlternateBouncerEnabled=$isModernAlternateBouncerEnabled") pw.println("showingUdfpsAltBouncer=$showingUdfpsBouncer") pw.println( "altBouncerInteractor#isAlternateBouncerVisible=" + @@ -473,22 +467,6 @@ constructor( private fun updateScaleFactor() { udfpsController.mOverlayParams?.scaleFactor?.let { view.setScaleFactor(it) } } - - private val legacyAlternateBouncer: LegacyAlternateBouncer = - object : LegacyAlternateBouncer { - override fun showAlternateBouncer(): Boolean { - return showUdfpsBouncer(true) - } - - override fun hideAlternateBouncer(): Boolean { - return showUdfpsBouncer(false) - } - - override fun isShowingAlternateBouncer(): Boolean { - return showingUdfpsBouncer - } - } - companion object { const val TAG = "UdfpsKeyguardViewController" } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index 99a10a33ab0f..37138114c740 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -44,7 +44,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.wm.shell.TaskViewFactory +import com.android.wm.shell.taskview.TaskViewFactory import java.util.Optional import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index c20af074c71e..d4ce9b699619 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -79,7 +79,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.asIndenting import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.indentIfPossible -import com.android.wm.shell.TaskViewFactory +import com.android.wm.shell.taskview.TaskViewFactory import dagger.Lazy import java.io.PrintWriter import java.text.Collator diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index 3d9eee4e9feb..5d608c3e3f9e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -36,7 +36,7 @@ import com.android.systemui.R import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.policy.KeyguardStateController -import com.android.wm.shell.TaskView +import com.android.wm.shell.taskview.TaskView /** * A dialog that provides an {@link TaskView}, allowing the application to provide @@ -44,13 +44,13 @@ import com.android.wm.shell.TaskView * The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}. */ class DetailDialog( - val activityContext: Context, - val broadcastSender: BroadcastSender, - val taskView: TaskView, - val pendingIntent: PendingIntent, - val cvh: ControlViewHolder, - val keyguardStateController: KeyguardStateController, - val activityStarter: ActivityStarter + val activityContext: Context, + val broadcastSender: BroadcastSender, + val taskView: TaskView, + val pendingIntent: PendingIntent, + val cvh: ControlViewHolder, + val keyguardStateController: KeyguardStateController, + val activityStarter: ActivityStarter ) : Dialog( activityContext, R.style.Theme_SystemUI_Dialog_Control_DetailPanel diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt index 1f89c917186a..9a231814a813 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt @@ -30,7 +30,7 @@ import android.graphics.drawable.shapes.RoundRectShape import android.os.Trace import com.android.systemui.R import com.android.systemui.util.boundsOnScreen -import com.android.wm.shell.TaskView +import com.android.wm.shell.taskview.TaskView import java.util.concurrent.Executor class PanelTaskViewController( diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 625a02801392..1a0fcea6ca87 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -38,7 +38,6 @@ import com.android.systemui.unfold.UnfoldLatencyTracker; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder; import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider; -import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.desktopmode.DesktopMode; @@ -49,16 +48,17 @@ import com.android.wm.shell.recents.RecentTasks; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.startingsurface.StartingSurface; import com.android.wm.shell.sysui.ShellInterface; +import com.android.wm.shell.taskview.TaskViewFactory; import com.android.wm.shell.transition.ShellTransitions; +import dagger.BindsInstance; +import dagger.Subcomponent; + import java.util.Map; import java.util.Optional; import javax.inject.Provider; -import dagger.BindsInstance; -import dagger.Subcomponent; - /** * An example Dagger Subcomponent for Core SysUI. * diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index d756f3a44655..17d2332a4dac 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -23,7 +23,6 @@ import androidx.annotation.Nullable; import com.android.systemui.SystemUIInitializerFactory; import com.android.systemui.tv.TvWMComponent; -import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.common.annotations.ShellMainThread; @@ -38,13 +37,14 @@ import com.android.wm.shell.recents.RecentTasks; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.startingsurface.StartingSurface; import com.android.wm.shell.sysui.ShellInterface; +import com.android.wm.shell.taskview.TaskViewFactory; import com.android.wm.shell.transition.ShellTransitions; -import java.util.Optional; - import dagger.BindsInstance; import dagger.Subcomponent; +import java.util.Optional; + /** * Dagger Subcomponent for WindowManager. This class explicitly describes the interfaces exported * from the WM component into the SysUI component (in diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java index 4b478cdca9f9..7c6a74864664 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java @@ -25,6 +25,7 @@ import static com.android.systemui.dreams.complication.ComplicationLayoutParams. import android.animation.Animator; import android.content.res.Resources; +import android.graphics.Region; import android.os.Handler; import android.util.MathUtils; import android.view.View; @@ -223,6 +224,9 @@ public class DreamOverlayContainerViewController extends mJitterStartTimeMillis = System.currentTimeMillis(); mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval); mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback); + final Region emptyRegion = Region.obtain(); + mView.getRootSurfaceControl().setTouchableRegion(emptyRegion); + emptyRegion.recycle(); // Start dream entry animations. Skip animations for low light clock. if (!mStateController.isLowLightActive()) { diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 4fe219de2cac..27f35db056e9 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -169,13 +169,6 @@ object Flags { @JvmField val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = false) - /** - * Whether to use the new alternate bouncer architecture, a refactor of and eventual replacement - * of the Alternate/Authentication Bouncer. No visual UI changes. - */ - // TODO(b/260619425): Tracking Bug - @JvmField val MODERN_ALTERNATE_BOUNCER = releasedFlag(219, "modern_alternate_bouncer") - /** Flag to control the migration of face auth to modern architecture. */ // TODO(b/262838215): Tracking bug @JvmField val FACE_AUTH_REFACTOR = unreleasedFlag(220, "face_auth_refactor") @@ -191,7 +184,7 @@ object Flags { // flag for controlling auto pin confirmation and material u shapes in bouncer @JvmField val AUTO_PIN_CONFIRMATION = - unreleasedFlag(224, "auto_pin_confirmation", "auto_pin_confirmation") + releasedFlag(224, "auto_pin_confirmation", "auto_pin_confirmation", teamfood = true) // TODO(b/262859270): Tracking Bug @JvmField val FALSING_OFF_FOR_UNFOLDED = releasedFlag(225, "falsing_off_for_unfolded") @@ -226,12 +219,16 @@ object Flags { /** Whether to inflate the bouncer view on a background thread. */ // TODO(b/272091103): Tracking Bug @JvmField - val ASYNC_INFLATE_BOUNCER = unreleasedFlag(229, "async_inflate_bouncer", teamfood = false) + val ASYNC_INFLATE_BOUNCER = unreleasedFlag(229, "async_inflate_bouncer", teamfood = true) /** Whether to inflate the bouncer view on a background thread. */ // TODO(b/273341787): Tracking Bug @JvmField - val PREVENT_BYPASS_KEYGUARD = unreleasedFlag(230, "prevent_bypass_keyguard") + val PREVENT_BYPASS_KEYGUARD = unreleasedFlag(230, "prevent_bypass_keyguard", teamfood = true) + + /** Whether to use a new data source for intents to run on keyguard dismissal. */ + @JvmField + val REFACTOR_KEYGUARD_DISMISS_INTENT = unreleasedFlag(231, "refactor_keyguard_dismiss_intent") // 300 - power menu // TODO(b/254512600): Tracking Bug @@ -288,7 +285,7 @@ object Flags { /** Enables Font Scaling Quick Settings tile */ // TODO(b/269341316): Tracking Bug @JvmField - val ENABLE_FONT_SCALING_TILE = unreleasedFlag(509, "enable_font_scaling_tile", teamfood = false) + val ENABLE_FONT_SCALING_TILE = unreleasedFlag(509, "enable_font_scaling_tile", teamfood = true) /** Enables new QS Edit Mode visual refresh */ // TODO(b/269787742): Tracking Bug @@ -638,7 +635,7 @@ object Flags { // TODO(b/269132640): Tracking Bug @JvmField val APP_PANELS_REMOVE_APPS_ALLOWED = - unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = false) + unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = true) // 2100 - Falsing Manager @JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps") @@ -700,7 +697,7 @@ object Flags { // TODO(b/272036292): Tracking Bug @JvmField val LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION = - unreleasedFlag(2602, "large_shade_granular_alpha_interpolation", teamfood = true) + releasedFlag(2602, "large_shade_granular_alpha_interpolation") // TODO(b/272805037): Tracking Bug @JvmField diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt index 84abf57cacf2..d5129a612b04 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt @@ -22,10 +22,10 @@ import android.content.Context import android.content.IntentFilter import android.hardware.biometrics.BiometricManager import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback -import android.os.Looper import android.os.UserHandle import android.util.Log import com.android.internal.widget.LockPatternUtils +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.biometrics.AuthController @@ -35,8 +35,8 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager +import com.android.systemui.keyguard.TAG import com.android.systemui.keyguard.shared.model.DevicePosture import com.android.systemui.user.data.repository.UserRepository import java.io.PrintWriter @@ -45,10 +45,12 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn @@ -93,8 +95,16 @@ interface BiometricSettingsRepository { * restricted to specific postures using [R.integer.config_face_auth_supported_posture] */ val isFaceAuthSupportedInCurrentPosture: Flow<Boolean> + + /** + * Whether the user manually locked down the device. This doesn't include device policy manager + * lockdown. + */ + val isCurrentUserInLockdown: Flow<Boolean> } +const val TAG = "BiometricsRepositoryImpl" + @SysUISingleton class BiometricSettingsRepositoryImpl @Inject @@ -103,19 +113,25 @@ constructor( lockPatternUtils: LockPatternUtils, broadcastDispatcher: BroadcastDispatcher, authController: AuthController, - userRepository: UserRepository, + private val userRepository: UserRepository, devicePolicyManager: DevicePolicyManager, @Application scope: CoroutineScope, @Background backgroundDispatcher: CoroutineDispatcher, biometricManager: BiometricManager?, - @Main looper: Looper, devicePostureRepository: DevicePostureRepository, dumpManager: DumpManager, ) : BiometricSettingsRepository, Dumpable { override val isFaceAuthSupportedInCurrentPosture: Flow<Boolean> + private val strongAuthTracker = StrongAuthTracker(userRepository, context) + + override val isCurrentUserInLockdown: Flow<Boolean> = + strongAuthTracker.currentUserAuthFlags.map { it.isInUserLockdown } + init { + Log.d(TAG, "Registering StrongAuthTracker") + lockPatternUtils.registerStrongAuthTracker(strongAuthTracker) dumpManager.registerDumpable(this) val configFaceAuthSupportedPosture = DevicePosture.toPosture( @@ -251,38 +267,14 @@ constructor( .stateIn(scope, SharingStarted.Eagerly, false) override val isStrongBiometricAllowed: StateFlow<Boolean> = - selectedUserId - .flatMapLatest { currUserId -> - conflatedCallbackFlow { - val callback = - object : LockPatternUtils.StrongAuthTracker(context, looper) { - override fun onStrongAuthRequiredChanged(userId: Int) { - if (currUserId != userId) { - return - } - - trySendWithFailureLogging( - isBiometricAllowedForUser(true, currUserId), - TAG - ) - } - - override fun onIsNonStrongBiometricAllowedChanged(userId: Int) { - // no-op - } - } - lockPatternUtils.registerStrongAuthTracker(callback) - awaitClose { lockPatternUtils.unregisterStrongAuthTracker(callback) } - } - } - .stateIn( - scope, - started = SharingStarted.Eagerly, - initialValue = - lockPatternUtils.isBiometricAllowedForUser( - userRepository.getSelectedUserInfo().id - ) + strongAuthTracker.isStrongBiometricAllowed.stateIn( + scope, + SharingStarted.Eagerly, + strongAuthTracker.isBiometricAllowedForUser( + true, + userRepository.getSelectedUserInfo().id ) + ) override val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> = selectedUserId @@ -300,9 +292,44 @@ constructor( userRepository.getSelectedUserInfo().id ) ) +} - companion object { - private const val TAG = "BiometricsRepositoryImpl" +private class StrongAuthTracker(private val userRepository: UserRepository, context: Context?) : + LockPatternUtils.StrongAuthTracker(context) { + + private val _authFlags = + MutableStateFlow( + StrongAuthenticationFlags(currentUserId, getStrongAuthForUser(currentUserId)) + ) + + val currentUserAuthFlags: Flow<StrongAuthenticationFlags> = + userRepository.selectedUserInfo + .map { it.id } + .distinctUntilChanged() + .flatMapLatest { currUserId -> + _authFlags + .filter { it.userId == currUserId } + .onEach { Log.d(TAG, "currentUser authFlags changed, new value: $it") } + .onStart { + emit( + StrongAuthenticationFlags( + currentUserId, + getStrongAuthForUser(currentUserId) + ) + ) + } + } + + val isStrongBiometricAllowed: Flow<Boolean> = + currentUserAuthFlags.map { isBiometricAllowedForUser(true, it.userId) } + + private val currentUserId + get() = userRepository.getSelectedUserInfo().id + + override fun onStrongAuthRequiredChanged(userId: Int) { + val newFlags = getStrongAuthForUser(userId) + _authFlags.value = StrongAuthenticationFlags(userId, newFlags) + Log.d(TAG, "onStrongAuthRequiredChanged for userId: $userId, flag value: $newFlags") } } @@ -314,3 +341,11 @@ private fun DevicePolicyManager.isFingerprintDisabled(userId: Int): Boolean = private fun DevicePolicyManager.isNotActive(userId: Int, policy: Int): Boolean = (getKeyguardDisabledFeatures(null, userId) and policy) == 0 + +private data class StrongAuthenticationFlags(val userId: Int, val flag: Int) { + val isInUserLockdown = containsFlag(flag, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) +} + +private fun containsFlag(haystack: Int, needle: Int): Boolean { + return haystack and needle != 0 +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt index 7c466845a923..4fa56ee8e4d2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt @@ -20,6 +20,7 @@ import android.hardware.biometrics.BiometricSourceType import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Dumpable +import com.android.systemui.biometrics.AuthController import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton @@ -29,6 +30,7 @@ import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.stateIn @@ -37,6 +39,17 @@ import kotlinx.coroutines.flow.stateIn interface DeviceEntryFingerprintAuthRepository { /** Whether the device entry fingerprint auth is locked out. */ val isLockedOut: StateFlow<Boolean> + + /** + * Whether the fingerprint sensor is currently listening, this doesn't mean that the user is + * actively authenticating. + */ + val isRunning: Flow<Boolean> + + /** + * Fingerprint sensor type present on the device, null if fingerprint sensor is not available. + */ + val availableFpSensorType: BiometricType? } /** @@ -50,6 +63,7 @@ interface DeviceEntryFingerprintAuthRepository { class DeviceEntryFingerprintAuthRepositoryImpl @Inject constructor( + val authController: AuthController, val keyguardUpdateMonitor: KeyguardUpdateMonitor, @Application scope: CoroutineScope, dumpManager: DumpManager, @@ -63,6 +77,12 @@ constructor( pw.println("isLockedOut=${isLockedOut.value}") } + override val availableFpSensorType: BiometricType? + get() = + if (authController.isUdfpsSupported) BiometricType.UNDER_DISPLAY_FINGERPRINT + else if (authController.isSfpsSupported) BiometricType.SIDE_FINGERPRINT + else if (authController.isRearFpsSupported) BiometricType.REAR_FINGERPRINT else null + override val isLockedOut: StateFlow<Boolean> = conflatedCallbackFlow { val sendLockoutUpdate = @@ -89,6 +109,32 @@ constructor( } .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false) + override val isRunning: Flow<Boolean> + get() = conflatedCallbackFlow { + val callback = + object : KeyguardUpdateMonitorCallback() { + override fun onBiometricRunningStateChanged( + running: Boolean, + biometricSourceType: BiometricSourceType? + ) { + if (biometricSourceType == BiometricSourceType.FINGERPRINT) { + trySendWithFailureLogging( + running, + TAG, + "Fingerprint running state changed" + ) + } + } + } + keyguardUpdateMonitor.registerCallback(callback) + trySendWithFailureLogging( + keyguardUpdateMonitor.isFingerprintDetectionRunning, + TAG, + "Initial fingerprint running state" + ) + awaitClose { keyguardUpdateMonitor.removeCallback(callback) } + } + companion object { const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl" } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt index aad4a2dd1af7..9b94cdbfe8dc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt @@ -16,15 +16,11 @@ package com.android.systemui.keyguard.domain.interactor -import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository import com.android.systemui.plugins.statusbar.StatusBarStateController -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.time.SystemClock import javax.inject.Inject @@ -41,13 +37,7 @@ constructor( private val biometricSettingsRepository: BiometricSettingsRepository, private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, private val systemClock: SystemClock, - private val keyguardUpdateMonitor: KeyguardUpdateMonitor, - featureFlags: FeatureFlags, ) { - val isModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER) - var legacyAlternateBouncer: LegacyAlternateBouncer? = null - var legacyAlternateBouncerVisibleTime: Long = NOT_VISIBLE - var receivedDownTouch = false val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible @@ -68,21 +58,8 @@ constructor( * @return whether alternateBouncer is visible */ fun show(): Boolean { - return when { - isModernAlternateBouncerEnabled -> { - bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint()) - isVisibleState() - } - canShowAlternateBouncerForFingerprint() -> { - if (legacyAlternateBouncer?.showAlternateBouncer() == true) { - legacyAlternateBouncerVisibleTime = systemClock.uptimeMillis() - true - } else { - false - } - } - else -> false - } + bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint()) + return isVisibleState() } /** @@ -94,21 +71,13 @@ constructor( */ fun hide(): Boolean { receivedDownTouch = false - return if (isModernAlternateBouncerEnabled) { - val wasAlternateBouncerVisible = isVisibleState() - bouncerRepository.setAlternateVisible(false) - wasAlternateBouncerVisible && !isVisibleState() - } else { - legacyAlternateBouncer?.hideAlternateBouncer() ?: false - } + val wasAlternateBouncerVisible = isVisibleState() + bouncerRepository.setAlternateVisible(false) + return wasAlternateBouncerVisible && !isVisibleState() } fun isVisibleState(): Boolean { - return if (isModernAlternateBouncerEnabled) { - bouncerRepository.alternateBouncerVisible.value - } else { - legacyAlternateBouncer?.isShowingAlternateBouncer ?: false - } + return bouncerRepository.alternateBouncerVisible.value } fun setAlternateBouncerUIAvailable(isAvailable: Boolean) { @@ -116,18 +85,13 @@ constructor( } fun canShowAlternateBouncerForFingerprint(): Boolean { - return if (isModernAlternateBouncerEnabled) { - bouncerRepository.alternateBouncerUIAvailable.value && - biometricSettingsRepository.isFingerprintEnrolled.value && - biometricSettingsRepository.isStrongBiometricAllowed.value && - biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value && - !deviceEntryFingerprintAuthRepository.isLockedOut.value && - !keyguardStateController.isUnlocked && - !statusBarStateController.isDozing - } else { - legacyAlternateBouncer != null && - keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true) - } + return bouncerRepository.alternateBouncerUIAvailable.value && + biometricSettingsRepository.isFingerprintEnrolled.value && + biometricSettingsRepository.isStrongBiometricAllowed.value && + biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value && + !deviceEntryFingerprintAuthRepository.isLockedOut.value && + !keyguardStateController.isUnlocked && + !statusBarStateController.isDozing } /** @@ -135,12 +99,8 @@ constructor( * alternate bouncer and show the primary bouncer. */ fun hasAlternateBouncerShownWithMinTime(): Boolean { - return if (isModernAlternateBouncerEnabled) { - (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) > - MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS - } else { - systemClock.uptimeMillis() - legacyAlternateBouncerVisibleTime > 200 - } + return (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) > + MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS } private fun maybeHide() { @@ -151,6 +111,5 @@ constructor( companion object { private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L - private const val NOT_VISIBLE = -1L } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt index 77541e931e08..33f4e2e24322 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt @@ -21,8 +21,6 @@ import android.content.res.ColorStateList import android.hardware.biometrics.BiometricSourceType import android.os.Handler import android.os.Trace -import android.os.UserHandle -import android.os.UserManager import android.util.Log import android.view.View import com.android.keyguard.KeyguardConstants @@ -106,10 +104,9 @@ constructor( val panelExpansionAmount: Flow<Float> = repository.panelExpansionAmount /** 0f = bouncer fully hidden. 1f = bouncer fully visible. */ val bouncerExpansion: Flow<Float> = - combine( - repository.panelExpansionAmount, - repository.primaryBouncerShow - ) { panelExpansion, primaryBouncerIsShowing -> + combine(repository.panelExpansionAmount, repository.primaryBouncerShow) { + panelExpansion, + primaryBouncerIsShowing -> if (primaryBouncerIsShowing) { 1f - panelExpansion } else { @@ -195,6 +192,7 @@ constructor( dismissCallbackRegistry.notifyDismissCancelled() } + repository.setPrimaryStartDisappearAnimation(null) falsingCollector.onBouncerHidden() keyguardStateController.notifyPrimaryBouncerShowing(false /* showing */) cancelShowRunnable() @@ -306,11 +304,8 @@ constructor( runnable.run() return } - val finishRunnable = Runnable { - runnable.run() - repository.setPrimaryStartDisappearAnimation(null) - } - repository.setPrimaryStartDisappearAnimation(finishRunnable) + + repository.setPrimaryStartDisappearAnimation(runnable) } /** Determine whether to show the side fps animation. */ diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 5704f8861f0e..e204defb82b6 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -119,15 +119,6 @@ public class LogModule { return factory.create("ShadeLog", 500, false); } - /** Provides a logging buffer for Shade height messages. */ - @Provides - @SysUISingleton - @ShadeHeightLog - public static LogBuffer provideShadeHeightLogBuffer(LogBufferFactory factory) { - return factory.create("ShadeHeightLog", 500 /* maxSize */); - } - - /** Provides a logging buffer for all logs related to managing notification sections. */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java index 35819e30fe45..9606bcf3fd9b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -78,7 +78,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private static final boolean DEBUG = true; private static final int HANDLE_BROADCAST_FAILED_DELAY = 3000; - private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); + protected final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final RecyclerView.LayoutManager mLayoutManager; final Context mContext; @@ -102,11 +102,13 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private int mListMaxHeight; private int mItemHeight; private WallpaperColors mWallpaperColors; - private Executor mExecutor; private boolean mShouldLaunchLeBroadcastDialog; + private boolean mIsLeBroadcastCallbackRegistered; MediaOutputBaseAdapter mAdapter; + protected Executor mExecutor; + private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> { ViewGroup.LayoutParams params = mDeviceListLayout.getLayoutParams(); int totalItemsHeight = mAdapter.getItemCount() * mItemHeight; @@ -274,17 +276,19 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements public void onStart() { super.onStart(); mMediaOutputController.start(this); - if(isBroadcastSupported()) { - mMediaOutputController.registerLeBroadcastServiceCallBack(mExecutor, + if (isBroadcastSupported() && !mIsLeBroadcastCallbackRegistered) { + mMediaOutputController.registerLeBroadcastServiceCallback(mExecutor, mBroadcastCallback); + mIsLeBroadcastCallbackRegistered = true; } } @Override public void onStop() { super.onStop(); - if(isBroadcastSupported()) { - mMediaOutputController.unregisterLeBroadcastServiceCallBack(mBroadcastCallback); + if (isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) { + mMediaOutputController.unregisterLeBroadcastServiceCallback(mBroadcastCallback); + mIsLeBroadcastCallbackRegistered = false; } mMediaOutputController.stop(); } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java index 12d6b7ccf5cd..f0ff1409faf1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java @@ -17,6 +17,10 @@ package com.android.systemui.media.dialog; import android.app.AlertDialog; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; @@ -34,8 +38,11 @@ import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.core.graphics.drawable.IconCompat; +import com.android.settingslib.media.BluetoothMediaDevice; +import com.android.settingslib.media.MediaDevice; import com.android.settingslib.qrcode.QrCodeGenerator; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastSender; @@ -49,7 +56,7 @@ import com.google.zxing.WriterException; */ @SysUISingleton public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { - private static final String TAG = "BroadcastDialog"; + private static final String TAG = "MediaOutputBroadcastDialog"; private ViewStub mBroadcastInfoArea; private ImageView mBroadcastQrCodeView; @@ -66,6 +73,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { private String mCurrentBroadcastName; private String mCurrentBroadcastCode; private boolean mIsStopbyUpdateBroadcastCode = false; + private TextWatcher mTextWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -105,6 +113,79 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } }; + private boolean mIsLeBroadcastAssistantCallbackRegistered; + + private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = + new BluetoothLeBroadcastAssistant.Callback() { + @Override + public void onSearchStarted(int reason) { + Log.d(TAG, "Assistant-onSearchStarted: " + reason); + } + + @Override + public void onSearchStartFailed(int reason) { + Log.d(TAG, "Assistant-onSearchStartFailed: " + reason); + } + + @Override + public void onSearchStopped(int reason) { + Log.d(TAG, "Assistant-onSearchStopped: " + reason); + } + + @Override + public void onSearchStopFailed(int reason) { + Log.d(TAG, "Assistant-onSearchStopFailed: " + reason); + } + + @Override + public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) { + Log.d(TAG, "Assistant-onSourceFound:"); + } + + @Override + public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId, int reason) { + Log.d(TAG, "Assistant-onSourceAdded: Device: " + sink + + ", sourceId: " + sourceId); + mMainThreadHandler.post(() -> refreshUi()); + } + + @Override + public void onSourceAddFailed(@NonNull BluetoothDevice sink, + @NonNull BluetoothLeBroadcastMetadata source, int reason) { + Log.d(TAG, "Assistant-onSourceAddFailed: Device: " + sink); + } + + @Override + public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceModified:"); + } + + @Override + public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceModifyFailed:"); + } + + @Override + public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceRemoved:"); + } + + @Override + public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceRemoveFailed:"); + } + + @Override + public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId, + @NonNull BluetoothLeBroadcastReceiveState state) { + Log.d(TAG, "Assistant-onReceiveStateChanged:"); + } + }; + static final int METADATA_BROADCAST_NAME = 0; static final int METADATA_BROADCAST_CODE = 1; @@ -131,6 +212,27 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } @Override + public void onStart() { + super.onStart(); + if (!mIsLeBroadcastAssistantCallbackRegistered) { + mIsLeBroadcastAssistantCallbackRegistered = true; + mMediaOutputController.registerLeBroadcastAssistantServiceCallback(mExecutor, + mBroadcastAssistantCallback); + } + connectBroadcastWithActiveDevice(); + } + + @Override + public void onStop() { + super.onStop(); + if (mIsLeBroadcastAssistantCallbackRegistered) { + mIsLeBroadcastAssistantCallbackRegistered = false; + mMediaOutputController.unregisterLeBroadcastAssistantServiceCallback( + mBroadcastAssistantCallback); + } + } + + @Override int getHeaderIconRes() { return 0; } @@ -224,6 +326,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { mCurrentBroadcastCode = getBroadcastMetadataInfo(METADATA_BROADCAST_CODE); mBroadcastName.setText(mCurrentBroadcastName); mBroadcastCode.setText(mCurrentBroadcastCode); + refresh(false); } private void inflateBroadcastInfoArea() { @@ -233,7 +336,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { private void setQrCodeView() { //get the Metadata, and convert to BT QR code format. - String broadcastMetadata = getBroadcastMetadata(); + String broadcastMetadata = getLocalBroadcastMetadataQrCodeString(); if (broadcastMetadata.isEmpty()) { //TDOD(b/226708424) Error handling for unable to generate the QR code bitmap return; @@ -249,6 +352,33 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } } + void connectBroadcastWithActiveDevice() { + //get the Metadata, and convert to BT QR code format. + BluetoothLeBroadcastMetadata broadcastMetadata = getBroadcastMetadata(); + if (broadcastMetadata == null) { + Log.e(TAG, "Error: There is no broadcastMetadata."); + return; + } + MediaDevice mediaDevice = mMediaOutputController.getCurrentConnectedMediaDevice(); + if (mediaDevice == null || !(mediaDevice instanceof BluetoothMediaDevice) + || !mediaDevice.isBLEDevice()) { + Log.e(TAG, "Error: There is no active BT LE device."); + return; + } + BluetoothDevice sink = ((BluetoothMediaDevice) mediaDevice).getCachedDevice().getDevice(); + Log.d(TAG, "The broadcastMetadata broadcastId: " + broadcastMetadata.getBroadcastId() + + ", the device: " + sink.getAnonymizedAddress()); + + if (mMediaOutputController.isThereAnyBroadcastSourceIntoSinkDevice(sink)) { + Log.d(TAG, "The sink device has the broadcast source now."); + return; + } + if (!mMediaOutputController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(sink, + broadcastMetadata, /*isGroupOp=*/ true)) { + Log.e(TAG, "Error: Source add failed"); + } + } + private void updateBroadcastCodeVisibility() { mBroadcastCode.setTransformationMethod( mIsPasswordHide ? HideReturnsTransformationMethod.getInstance() @@ -282,7 +412,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { mAlertDialog.show(); } - private String getBroadcastMetadata() { + private String getLocalBroadcastMetadataQrCodeString() { + return mMediaOutputController.getLocalBroadcastMetadataQrCodeString(); + } + + private BluetoothLeBroadcastMetadata getBroadcastMetadata() { return mMediaOutputController.getBroadcastMetadata(); } @@ -314,6 +448,17 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } @Override + public boolean isBroadcastSupported() { + boolean isBluetoothLeDevice = false; + if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) { + isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice( + mMediaOutputController.getCurrentConnectedMediaDevice()); + } + + return mMediaOutputController.isBroadcastSupported() && isBluetoothLeDevice; + } + + @Override public void handleLeBroadcastStarted() { mRetryCount = 0; if (mAlertDialog != null) { @@ -332,6 +477,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { @Override public void handleLeBroadcastMetadataChanged() { + Log.d(TAG, "handleLeBroadcastMetadataChanged:"); refreshUi(); } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index f3f17d1c7144..9ebc8e410013 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -25,7 +25,11 @@ import android.app.AlertDialog; import android.app.KeyguardManager; import android.app.Notification; import android.app.WallpaperColors; +import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcast; +import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -66,6 +70,7 @@ import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.InfoMediaManager; @@ -1049,7 +1054,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, ALLOWLIST_DURATION_MS); } - String getBroadcastMetadata() { + String getLocalBroadcastMetadataQrCodeString() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { @@ -1061,6 +1066,17 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, return metadata != null ? metadata.convertToQrCodeString() : ""; } + BluetoothLeBroadcastMetadata getBroadcastMetadata() { + LocalBluetoothLeBroadcast broadcast = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); + if (broadcast == null) { + Log.d(TAG, "getBroadcastMetadata: LE Audio Broadcast is null"); + return null; + } + + return broadcast.getLatestBluetoothLeBroadcastMetadata(); + } + boolean isActiveRemoteDevice(@NonNull MediaDevice device) { final List<String> features = device.getFeatures(); return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK) @@ -1121,7 +1137,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, return true; } - void registerLeBroadcastServiceCallBack( + void registerLeBroadcastServiceCallback( @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = @@ -1130,10 +1146,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, Log.d(TAG, "The broadcast profile is null"); return; } + Log.d(TAG, "Register LE broadcast callback"); broadcast.registerServiceCallBack(executor, callback); } - void unregisterLeBroadcastServiceCallBack( + void unregisterLeBroadcastServiceCallback( @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); @@ -1141,9 +1158,59 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, Log.d(TAG, "The broadcast profile is null"); return; } + Log.d(TAG, "Unregister LE broadcast callback"); broadcast.unregisterServiceCallBack(callback); } + boolean isThereAnyBroadcastSourceIntoSinkDevice(BluetoothDevice sink) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return false; + } + List<BluetoothLeBroadcastReceiveState> sourceList = assistant.getAllSources(sink); + Log.d(TAG, "isThereAnyBroadcastSourceIntoSinkDevice: List size: " + sourceList.size()); + return !sourceList.isEmpty(); + } + + boolean addSourceIntoSinkDeviceWithBluetoothLeAssistant(BluetoothDevice sink, + BluetoothLeBroadcastMetadata metadata, boolean isGroupOp) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return false; + } + assistant.addSource(sink, metadata, isGroupOp); + return true; + } + + void registerLeBroadcastAssistantServiceCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull BluetoothLeBroadcastAssistant.Callback callback) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return; + } + Log.d(TAG, "Register LE broadcast assistant callback"); + assistant.registerServiceCallBack(executor, callback); + } + + void unregisterLeBroadcastAssistantServiceCallback( + @NonNull BluetoothLeBroadcastAssistant.Callback callback) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return; + } + Log.d(TAG, "Unregister LE broadcast assistant callback"); + assistant.unregisterServiceCallBack(callback); + } + private boolean isPlayBackInfoLocal() { return mMediaController != null && mMediaController.getPlaybackInfo() != null diff --git a/packages/SystemUI/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractor.kt index 33b3087678e1..e352c613ad86 100644 --- a/packages/SystemUI/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractor.kt @@ -22,7 +22,6 @@ import android.view.ViewConfiguration import com.android.systemui.classifier.Classifier import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.multishade.shared.math.isZero import com.android.systemui.multishade.shared.model.ProxiedInputModel @@ -48,7 +47,6 @@ constructor( @Application private val applicationScope: CoroutineScope, private val multiShadeInteractor: MultiShadeInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, - private val bouncerInteractor: PrimaryBouncerInteractor, private val falsingManager: FalsingManager, ) { @@ -98,7 +96,7 @@ constructor( currentY = event.y, pointerId = event.getPointerId(0), isDraggingHorizontally = false, - draggedVertically = Dragged.NONE, + isDraggingShade = false, ) false @@ -108,38 +106,28 @@ constructor( val pointerIndex = event.findPointerIndex(it.pointerId) val currentX = event.getX(pointerIndex) val currentY = event.getY(pointerIndex) - if (!it.isDraggingHorizontally && it.draggedVertically == Dragged.NONE) { + if (!it.isDraggingHorizontally && !it.isDraggingShade) { val xDistanceTravelled = currentX - it.initialX val yDistanceTravelled = currentY - it.initialY val touchSlop = ViewConfiguration.get(applicationContext).scaledTouchSlop interactionState = when { - abs(yDistanceTravelled) > touchSlop -> - it.copy( - draggedVertically = - if (yDistanceTravelled > 0) { - Dragged.SHADE - } else { - Dragged.BOUNCER - } - ) + yDistanceTravelled > touchSlop -> it.copy(isDraggingShade = true) abs(xDistanceTravelled) > touchSlop -> - it.copy( - isDraggingHorizontally = true, - ) + it.copy(isDraggingHorizontally = true) else -> interactionState } } } - // We want to intercept the rest of the gesture if we're dragging. - interactionState.isDraggingVertically() + // We want to intercept the rest of the gesture if we're dragging the shade. + isDraggingShade() } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> - // Make sure that we intercept the up or cancel if we're dragging, to handle drag - // end and cancel. - interactionState.isDraggingVertically() + // Make sure that we intercept the up or cancel if we're dragging the shade, to + // handle drag end or cancel. + isDraggingShade() else -> false } } @@ -156,35 +144,23 @@ constructor( return when (event.actionMasked) { MotionEvent.ACTION_MOVE -> { interactionState?.let { - if (it.draggedVertically != Dragged.NONE) { + if (it.isDraggingShade) { val pointerIndex = event.findPointerIndex(it.pointerId) val previousY = it.currentY val currentY = event.getY(pointerIndex) - interactionState = - it.copy( - currentY = currentY, - ) + interactionState = it.copy(currentY = currentY) - when (it.draggedVertically) { - Dragged.SHADE -> { - val yDragAmountPx = currentY - previousY + val yDragAmountPx = currentY - previousY - if (yDragAmountPx != 0f) { - multiShadeInteractor.sendProxiedInput( - ProxiedInputModel.OnDrag( - xFraction = event.x / viewWidthPx, - yDragAmountPx = yDragAmountPx, - ) - ) - } - true - } - Dragged.BOUNCER -> { - bouncerInteractor.show(isScrimmed = true) - false - } - else -> false + if (yDragAmountPx != 0f) { + multiShadeInteractor.sendProxiedInput( + ProxiedInputModel.OnDrag( + xFraction = event.x / viewWidthPx, + yDragAmountPx = yDragAmountPx, + ) + ) } + true } else { false } @@ -192,9 +168,10 @@ constructor( ?: false } MotionEvent.ACTION_UP -> { - if (interactionState?.draggedVertically == Dragged.SHADE) { - // We finished dragging. Record that so the multi-shade framework can issue a - // fling, if the velocity reached in the drag was high enough, for example. + if (isDraggingShade()) { + // We finished dragging the shade. Record that so the multi-shade framework can + // issue a fling, if the velocity reached in the drag was high enough, for + // example. multiShadeInteractor.sendProxiedInput(ProxiedInputModel.OnDragEnd) if (falsingManager.isFalseTouch(Classifier.SHADE_DRAG)) { @@ -205,8 +182,28 @@ constructor( interactionState = null true } + MotionEvent.ACTION_POINTER_UP -> { + val removedPointerId = event.getPointerId(event.actionIndex) + if (removedPointerId == interactionState?.pointerId && event.pointerCount > 1) { + // We removed the original pointer but there must be another pointer because the + // gesture is still ongoing. Let's switch to that pointer. + interactionState = + event.firstUnremovedPointerId(removedPointerId)?.let { replacementPointerId + -> + interactionState?.copy( + pointerId = replacementPointerId, + // We want to update the currentY of our state so that the + // transition to the next pointer doesn't report a big jump between + // the Y coordinate of the removed pointer and the Y coordinate of + // the replacement pointer. + currentY = event.getY(replacementPointerId), + ) + } + } + true + } MotionEvent.ACTION_CANCEL -> { - if (interactionState?.draggedVertically == Dragged.SHADE) { + if (isDraggingShade()) { // Our drag gesture was canceled by the system. This happens primarily in one of // two occasions: (a) the parent view has decided to intercept the gesture // itself and/or route it to a different child view or (b) the pointer has @@ -219,10 +216,6 @@ constructor( if (falsingManager.isFalseTouch(Classifier.SHADE_DRAG)) { multiShadeInteractor.collapseAll() } - } else if (interactionState?.draggedVertically == Dragged.BOUNCER) { - if (falsingManager.isFalseTouch(Classifier.BOUNCER_UNLOCK)) { - bouncerInteractor.hide() - } } interactionState = null @@ -239,21 +232,24 @@ constructor( val pointerId: Int, /** Whether the current gesture is dragging horizontally. */ val isDraggingHorizontally: Boolean, - /** The UI component that is being dragged vertically, if any. */ - val draggedVertically: Dragged, + /** Whether the current gesture is dragging the shade vertically. */ + val isDraggingShade: Boolean, ) - /** Enumerates the UI components that can be dragged by the user. */ - private enum class Dragged { - /** The bouncer is being dragged by the user. */ - BOUNCER, - /** A shade is being dragged by the user. */ - SHADE, - /** No UI component is being dragged by the user. */ - NONE, + private fun isDraggingShade(): Boolean { + return interactionState?.isDraggingShade ?: false } - private fun InteractionState?.isDraggingVertically(): Boolean { - return this?.draggedVertically != Dragged.NONE + /** + * Returns the index of the first pointer that is not [removedPointerId] or `null`, if there is + * no other pointer. + */ + private fun MotionEvent.firstUnremovedPointerId(removedPointerId: Int): Int? { + return (0 until pointerCount) + .firstOrNull { pointerIndex -> + val pointerId = getPointerId(pointerIndex) + pointerId != removedPointerId + } + ?.let { pointerIndex -> getPointerId(pointerIndex) } } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 5b0a4bb396a1..580facdda7d7 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -226,6 +226,18 @@ public class NavigationBarController implements } } + private boolean shouldCreateNavBarAndTaskBar(int displayId) { + final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); + + try { + return wms.hasNavigationBar(displayId); + } catch (RemoteException e) { + // Cannot get wms, just return false with warning message. + Log.w(TAG, "Cannot get WindowManager."); + return false; + } + } + /** @see #initializeTaskbarIfNecessary() */ private boolean updateNavbarForTaskbar() { boolean taskbarShown = initializeTaskbarIfNecessary(); @@ -238,8 +250,8 @@ public class NavigationBarController implements /** @return {@code true} if taskbar is enabled, false otherwise */ private boolean initializeTaskbarIfNecessary() { // Enable for large screens or (phone AND flag is set); assuming phone = !mIsLargeScreen - boolean taskbarEnabled = mIsLargeScreen || mFeatureFlags.isEnabled( - Flags.HIDE_NAVBAR_WINDOW); + boolean taskbarEnabled = (mIsLargeScreen || mFeatureFlags.isEnabled( + Flags.HIDE_NAVBAR_WINDOW)) && shouldCreateNavBarAndTaskBar(mContext.getDisplayId()); if (taskbarEnabled) { Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary"); @@ -331,23 +343,16 @@ public class NavigationBarController implements final int displayId = display.getDisplayId(); final boolean isOnDefaultDisplay = displayId == mDisplayTracker.getDefaultDisplayId(); + if (!shouldCreateNavBarAndTaskBar(displayId)) { + return; + } + // We may show TaskBar on the default display for large screen device. Don't need to create // navigation bar for this case. if (isOnDefaultDisplay && initializeTaskbarIfNecessary()) { return; } - final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); - - try { - if (!wms.hasNavigationBar(displayId)) { - return; - } - } catch (RemoteException e) { - // Cannot get wms, just return with warning message. - Log.w(TAG, "Cannot get WindowManager."); - return; - } final Context context = isOnDefaultDisplay ? mContext : mContext.createDisplayContext(display); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt index 0d5a3fd0854d..a29eb3bda748 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt @@ -56,7 +56,8 @@ private const val PX_PER_MS = 1 internal const val MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION = 300L private const val MIN_DURATION_ACTIVE_AFTER_INACTIVE_ANIMATION = 130L private const val MIN_DURATION_CANCELLED_ANIMATION = 200L -private const val MIN_DURATION_COMMITTED_ANIMATION = 120L +private const val MIN_DURATION_COMMITTED_ANIMATION = 80L +private const val MIN_DURATION_COMMITTED_AFTER_FLING_ANIMATION = 120L private const val MIN_DURATION_INACTIVE_BEFORE_FLUNG_ANIMATION = 50L private const val MIN_DURATION_FLING_ANIMATION = 160L @@ -918,7 +919,7 @@ class BackPanelController internal constructor( if (previousState == GestureState.FLUNG) { updateRestingArrowDimens() mainHandler.postDelayed(onEndSetGoneStateListener.runnable, - MIN_DURATION_COMMITTED_ANIMATION) + MIN_DURATION_COMMITTED_AFTER_FLING_ANIMATION) } else { mView.popScale(POP_ON_FLING_SCALE) mainHandler.postDelayed(onAlphaEndSetGoneStateListener.runnable, diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 498d5c0dedb4..26b0e8dd9895 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -18,7 +18,8 @@ package com.android.systemui.navigationbar.gestural; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION; import static com.android.systemui.classifier.Classifier.BACK_GESTURE; -import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe; +import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadFourFingerSwipe; +import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadMultiFingerSwipe; import android.annotation.NonNull; import android.app.ActivityManager; @@ -81,6 +82,7 @@ import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.shared.tracing.ProtoTraceable; +import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto; import com.android.systemui.tracing.nano.SystemUiTraceProto; @@ -206,6 +208,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack private final Provider<BackGestureTfClassifierProvider> mBackGestureTfClassifierProviderProvider; private final FeatureFlags mFeatureFlags; + private final Provider<LightBarController> mLightBarControllerProvider; // The left side edge width where touch down is allowed private int mEdgeWidthLeft; @@ -351,7 +354,8 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack FalsingManager falsingManager, Provider<NavigationBarEdgePanel> navigationBarEdgePanelProvider, Provider<BackGestureTfClassifierProvider> backGestureTfClassifierProviderProvider, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + Provider<LightBarController> lightBarControllerProvider) { mContext = context; mDisplayId = context.getDisplayId(); mMainExecutor = executor; @@ -371,6 +375,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack mNavBarEdgePanelProvider = navigationBarEdgePanelProvider; mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider; mFeatureFlags = featureFlags; + mLightBarControllerProvider = lightBarControllerProvider; mLastReportedConfig.setTo(mContext.getResources().getConfiguration()); ComponentName recentsComponentName = ComponentName.unflattenFromString( context.getString(com.android.internal.R.string.config_recentsComponentName)); @@ -888,8 +893,9 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack } private void onMotionEvent(MotionEvent ev) { - boolean isTrackpadEvent = isTrackpadThreeFingerSwipe(mIsTrackpadGestureFeaturesEnabled, ev); int action = ev.getActionMasked(); + boolean isTrackpadMultiFingerSwipe = isTrackpadMultiFingerSwipe( + mIsTrackpadGestureFeaturesEnabled, ev); if (action == MotionEvent.ACTION_DOWN) { if (DEBUG_MISSING_GESTURE) { Log.d(DEBUG_MISSING_GESTURE_TAG, "Start gesture: " + ev); @@ -898,7 +904,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack // Verify if this is in within the touch region and we aren't in immersive mode, and // either the bouncer is showing or the notification panel is hidden mInputEventReceiver.setBatchingEnabled(false); - if (isTrackpadEvent) { + if (isTrackpadMultiFingerSwipe) { // Since trackpad gestures don't have zones, this will be determined later by the // direction of the gesture. {@code mIsOnLeftEdge} is set to false to begin with. mDeferSetIsOnLeftEdge = true; @@ -913,17 +919,17 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack // Trackpad back gestures don't have zones, so we don't need to check if the down event // is within insets. mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed - && (isTrackpadEvent || isWithinInsets) + && (isTrackpadMultiFingerSwipe || isWithinInsets) && !mGestureBlockingActivityRunning && !QuickStepContract.isBackGestureDisabled(mSysUiFlags) - && (isValidTrackpadBackGesture(isTrackpadEvent) || isWithinTouchRegion( - (int) ev.getX(), (int) ev.getY())); + && (isValidTrackpadBackGesture(isTrackpadMultiFingerSwipe) + || isWithinTouchRegion((int) ev.getX(), (int) ev.getY())); if (mAllowGesture) { mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge); mEdgeBackPlugin.onMotionEvent(ev); dispatchToBackAnimation(ev); } - if (mLogGesture || isTrackpadEvent) { + if (mLogGesture || isTrackpadMultiFingerSwipe) { mDownPoint.set(ev.getX(), ev.getY()); mEndPoint.set(-1, -1); mThresholdCrossed = false; @@ -932,15 +938,16 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack // For debugging purposes, only log edge points (isWithinInsets ? mGestureLogInsideInsets : mGestureLogOutsideInsets).log(String.format( "Gesture [%d,alw=%B,%B,%B,%B,%B,%B,disp=%s,wl=%d,il=%d,wr=%d,ir=%d,excl=%s]", - System.currentTimeMillis(), isTrackpadEvent, mAllowGesture, mIsOnLeftEdge, - mDeferSetIsOnLeftEdge, mIsBackGestureAllowed, + System.currentTimeMillis(), isTrackpadMultiFingerSwipe, mAllowGesture, + mIsOnLeftEdge, mDeferSetIsOnLeftEdge, mIsBackGestureAllowed, QuickStepContract.isBackGestureDisabled(mSysUiFlags), mDisplaySize, mEdgeWidthLeft, mLeftInset, mEdgeWidthRight, mRightInset, mExcludeRegion)); } else if (mAllowGesture || mLogGesture) { if (!mThresholdCrossed) { mEndPoint.x = (int) ev.getX(); mEndPoint.y = (int) ev.getY(); - if (action == MotionEvent.ACTION_POINTER_DOWN && !isTrackpadEvent) { + if (action == MotionEvent.ACTION_POINTER_DOWN && (!isTrackpadMultiFingerSwipe + || isTrackpadFourFingerSwipe(mIsTrackpadGestureFeaturesEnabled, ev))) { if (mAllowGesture) { logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH); if (DEBUG_MISSING_GESTURE) { @@ -952,7 +959,11 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack mLogGesture = false; return; } else if (action == MotionEvent.ACTION_MOVE) { - if (isTrackpadEvent && mDeferSetIsOnLeftEdge) { + if (isTrackpadFourFingerSwipe(isTrackpadMultiFingerSwipe, ev)) { + cancelGesture(ev); + return; + } + if (isTrackpadMultiFingerSwipe && mDeferSetIsOnLeftEdge) { // mIsOnLeftEdge is determined by the relative position between the down // and the current motion event for trackpad gestures instead of zoning. mIsOnLeftEdge = mEndPoint.x > mDownPoint.x; @@ -1048,6 +1059,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack if (DEBUG_MISSING_GESTURE) { Log.d(DEBUG_MISSING_GESTURE_TAG, "Update display size: mDisplaySize=" + mDisplaySize); } + if (mEdgeBackPlugin != null) { mEdgeBackPlugin.setDisplaySize(mDisplaySize); } @@ -1141,6 +1153,13 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack public void setBackAnimation(BackAnimation backAnimation) { mBackAnimation = backAnimation; updateBackAnimationThresholds(); + if (mLightBarControllerProvider.get() != null) { + mBackAnimation.setStatusBarCustomizer((appearance) -> { + mMainExecutor.execute(() -> + mLightBarControllerProvider.get() + .customizeStatusBarAppearance(appearance)); + }); + } } /** @@ -1168,6 +1187,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack private final Provider<BackGestureTfClassifierProvider> mBackGestureTfClassifierProviderProvider; private final FeatureFlags mFeatureFlags; + private final Provider<LightBarController> mLightBarControllerProvider; @Inject public Factory(OverviewProxyService overviewProxyService, @@ -1187,7 +1207,8 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack Provider<NavigationBarEdgePanel> navBarEdgePanelProvider, Provider<BackGestureTfClassifierProvider> backGestureTfClassifierProviderProvider, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + Provider<LightBarController> lightBarControllerProvider) { mOverviewProxyService = overviewProxyService; mSysUiState = sysUiState; mPluginManager = pluginManager; @@ -1205,6 +1226,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack mNavBarEdgePanelProvider = navBarEdgePanelProvider; mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider; mFeatureFlags = featureFlags; + mLightBarControllerProvider = lightBarControllerProvider; } /** Construct a {@link EdgeBackGestureHandler}. */ @@ -1227,7 +1249,8 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack mFalsingManager, mNavBarEdgePanelProvider, mBackGestureTfClassifierProviderProvider, - mFeatureFlags); + mFeatureFlags, + mLightBarControllerProvider); } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt index 35b6c15d92f7..6ce6f0d5f722 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt @@ -219,7 +219,7 @@ data class EdgePanelParams(private var resources: Resources) { height = getDimen(R.dimen.navigation_edge_active_background_height), edgeCornerRadius = getDimen(R.dimen.navigation_edge_active_edge_corners), farCornerRadius = getDimen(R.dimen.navigation_edge_active_far_corners), - widthSpring = createSpring(650f, 0.75f), + widthSpring = createSpring(850f, 0.75f), heightSpring = createSpring(10000f, 1f), edgeCornerRadiusSpring = createSpring(600f, 0.36f), farCornerRadiusSpring = createSpring(2500f, 0.855f), @@ -274,8 +274,8 @@ data class EdgePanelParams(private var resources: Resources) { farCornerRadiusSpring = flungCommittedFarCornerSpring, alphaSpring = createSpring(1400f, 1f), ), - scale = 0.85f, - scaleSpring = createSpring(6000f, 1f), + scale = 0.86f, + scaleSpring = createSpring(5700f, 1f), ) flungIndicator = committedIndicator.copy( diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java index 9e2b6d3cd898..50e8aa7b2046 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/Utilities.java @@ -22,10 +22,21 @@ import android.view.MotionEvent; public final class Utilities { - public static boolean isTrackpadThreeFingerSwipe(boolean isTrackpadGestureFeaturesEnabled, + public static boolean isTrackpadMultiFingerSwipe(boolean isTrackpadGestureFeaturesEnabled, MotionEvent event) { return isTrackpadGestureFeaturesEnabled - && event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE + && event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE; + } + + public static boolean isTrackpadThreeFingerSwipe(boolean isTrackpadGestureFeaturesEnabled, + MotionEvent event) { + return isTrackpadMultiFingerSwipe(isTrackpadGestureFeaturesEnabled, event) && event.getPointerCount() == 3; } + + public static boolean isTrackpadFourFingerSwipe(boolean isTrackpadGestureFeaturesEnabled, + MotionEvent event) { + return isTrackpadMultiFingerSwipe(isTrackpadGestureFeaturesEnabled, event) + && event.getPointerCount() == 4; + } } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt index 2d7861be2da9..f5c0a94d07f2 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt @@ -174,21 +174,26 @@ constructor( infoReference.set(info) - // TODO(b/266686199): We should handle when app not available. For now, we log. - val intent = createNoteTaskIntent(info) try { + // TODO(b/266686199): We should handle when app not available. For now, we log. logDebug { "onShowNoteTask - start: $info on user#${user.identifier}" } when (info.launchMode) { is NoteTaskLaunchMode.AppBubble -> { // TODO: provide app bubble icon + val intent = createNoteTaskIntent(info) bubbles.showOrHideAppBubble(intent, user, null /* icon */) // App bubble logging happens on `onBubbleExpandChanged`. logDebug { "onShowNoteTask - opened as app bubble: $info" } } is NoteTaskLaunchMode.Activity -> { if (activityManager.isInForeground(info.packageName)) { - logDebug { "onShowNoteTask - already opened as activity: $info" } + // Force note task into background by calling home. + val intent = createHomeIntent() + context.startActivityAsUser(intent, user) + eventLogger.logNoteTaskClosed(info) + logDebug { "onShowNoteTask - closed as activity: $info" } } else { + val intent = createNoteTaskIntent(info) context.startActivityAsUser(intent, user) eventLogger.logNoteTaskOpened(info) logDebug { "onShowNoteTask - opened as activity: $info" } @@ -199,7 +204,7 @@ constructor( } catch (e: ActivityNotFoundException) { logDebug { "onShowNoteTask - failed: $info" } } - logDebug { "onShowNoteTask - compoleted: $info" } + logDebug { "onShowNoteTask - completed: $info" } } /** @@ -306,3 +311,10 @@ private fun createNoteTaskIntent(info: NoteTaskInfo): Intent = private inline fun Any.logDebug(message: () -> String) { if (Build.IS_DEBUGGABLE) Log.d(this::class.java.simpleName.orEmpty(), message()) } + +/** Creates an [Intent] which forces the current app to background by calling home. */ +private fun createHomeIntent(): Intent = + Intent(Intent.ACTION_MAIN).apply { + addCategory(Intent.CATEGORY_HOME) + flags = Intent.FLAG_ACTIVITY_NEW_TASK + } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index 9ece72d2ca7f..6be74a0b5646 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -40,13 +40,12 @@ public interface QSHost extends PanelInteractor { /** * Returns the default QS tiles for the context. - * @param context the context to obtain the resources from + * @param res the resources to use to determine the default tiles * @return a list of specs of the default tiles */ - static List<String> getDefaultSpecs(Context context) { + static List<String> getDefaultSpecs(Resources res) { final ArrayList<String> tiles = new ArrayList(); - final Resources res = context.getResources(); final String defaultTileList = res.getString(R.string.quick_settings_tiles_default); tiles.addAll(Arrays.asList(defaultTileList.split(","))); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 0ead97976ad9..8bbdeeda356c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -600,7 +600,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P if (tile.isEmpty()) continue; if (tile.equals("default")) { if (!addedDefault) { - List<String> defaultSpecs = QSHost.getDefaultSpecs(context); + List<String> defaultSpecs = QSHost.getDefaultSpecs(context.getResources()); for (String spec : defaultSpecs) { if (!addedSpecs.contains(spec)) { tiles.add(spec); diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java index a319fb8d8756..4002ac3aa120 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java @@ -175,7 +175,7 @@ public class QSCustomizerController extends ViewController<QSCustomizer> { private void reset() { - mTileAdapter.resetTileSpecs(QSHost.getDefaultSpecs(getContext())); + mTileAdapter.resetTileSpecs(QSHost.getDefaultSpecs(getContext().getResources())); } public boolean isCustomizing() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java index cfe93132c044..dffe7fd5f818 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java @@ -29,6 +29,7 @@ import com.android.systemui.qs.AutoAddTracker; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.external.QSExternalModule; +import com.android.systemui.qs.pipeline.dagger.QSPipelineModule; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.ManagedProfileController; @@ -40,14 +41,14 @@ import com.android.systemui.statusbar.policy.SafetyController; import com.android.systemui.statusbar.policy.WalletController; import com.android.systemui.util.settings.SecureSettings; -import java.util.Map; - -import javax.inject.Named; - import dagger.Module; import dagger.Provides; import dagger.multibindings.Multibinds; +import java.util.Map; + +import javax.inject.Named; + /** * Module for QS dependencies */ @@ -56,7 +57,8 @@ import dagger.multibindings.Multibinds; MediaModule.class, QSExternalModule.class, QSFlagsModule.class, - QSHostModule.class + QSHostModule.class, + QSPipelineModule.class, } ) public interface QSModule { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 5e4f53181706..42536fef17aa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -30,6 +30,7 @@ import android.service.quicksettings.IQSService; import android.service.quicksettings.Tile; import android.util.ArrayMap; import android.util.Log; +import android.util.SparseArrayMap; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -64,7 +65,7 @@ public class TileServices extends IQSService.Stub { private static final String TAG = "TileServices"; private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>(); - private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>(); + private final SparseArrayMap<ComponentName, CustomTile> mTiles = new SparseArrayMap<>(); private final ArrayMap<IBinder, CustomTile> mTokenMap = new ArrayMap<>(); private final Context mContext; private final Handler mMainHandler; @@ -112,10 +113,11 @@ public class TileServices extends IQSService.Stub { public TileServiceManager getTileWrapper(CustomTile tile) { ComponentName component = tile.getComponent(); + int userId = tile.getUser(); TileServiceManager service = onCreateTileService(component, mBroadcastDispatcher); synchronized (mServices) { mServices.put(tile, service); - mTiles.put(component, tile); + mTiles.add(userId, component, tile); mTokenMap.put(service.getToken(), tile); } // Makes sure binding only happens after the maps have been populated @@ -135,7 +137,7 @@ public class TileServices extends IQSService.Stub { service.handleDestroy(); mServices.remove(tile); mTokenMap.remove(service.getToken()); - mTiles.remove(tile.getComponent()); + mTiles.delete(tile.getUser(), tile.getComponent()); final String slot = getStatusBarIconSlotName(tile.getComponent()); mMainHandler.post(() -> mStatusBarIconController.removeIconForTile(slot)); } @@ -188,9 +190,10 @@ public class TileServices extends IQSService.Stub { private void requestListening(ComponentName component) { synchronized (mServices) { - CustomTile customTile = getTileForComponent(component); + int userId = mUserTracker.getUserId(); + CustomTile customTile = getTileForUserAndComponent(userId, component); if (customTile == null) { - Log.d("TileServices", "Couldn't find tile for " + component); + Log.d(TAG, "Couldn't find tile for " + component + "(" + userId + ")"); return; } TileServiceManager service = mServices.get(customTile); @@ -362,9 +365,9 @@ public class TileServices extends IQSService.Stub { } @Nullable - private CustomTile getTileForComponent(ComponentName component) { + private CustomTile getTileForUserAndComponent(int userId, ComponentName component) { synchronized (mServices) { - return mTiles.get(component); + return mTiles.get(userId, component); } } @@ -395,4 +398,5 @@ public class TileServices extends IQSService.Stub { return -Integer.compare(left.getBindPriority(), right.getBindPriority()); } }; + } diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt index 8387c1dd60a5..b394a079fb00 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt @@ -89,7 +89,7 @@ interface FooterActionsInteractor { fun showSettings(expandable: Expandable) /** Show the user switcher. */ - fun showUserSwitcher(context: Context, expandable: Expandable) + fun showUserSwitcher(expandable: Expandable) } @SysUISingleton @@ -177,7 +177,7 @@ constructor( ) } - override fun showUserSwitcher(context: Context, expandable: Expandable) { - userInteractor.showUserSwitcher(context, expandable) + override fun showUserSwitcher(expandable: Expandable) { + userInteractor.showUserSwitcher(expandable) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt index f170ac1d9d4e..3a9098ab49d3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt @@ -230,7 +230,7 @@ class FooterActionsViewModel( return } - footerActionsInteractor.showUserSwitcher(context, expandable) + footerActionsInteractor.showUserSwitcher(expandable) } private fun onSettingsButtonClicked(expandable: Expandable) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt new file mode 100644 index 000000000000..00f0a67dbe22 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.dagger + +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.LogBufferFactory +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository +import com.android.systemui.qs.pipeline.data.repository.TileSpecSettingsRepository +import com.android.systemui.qs.pipeline.prototyping.PrototypeCoreStartable +import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +abstract class QSPipelineModule { + + /** Implementation for [TileSpecRepository] */ + @Binds + abstract fun provideTileSpecRepository(impl: TileSpecSettingsRepository): TileSpecRepository + + @Binds + @IntoMap + @ClassKey(PrototypeCoreStartable::class) + abstract fun providePrototypeCoreStartable(startable: PrototypeCoreStartable): CoreStartable + + companion object { + /** + * Provides a logging buffer for all logs related to the new Quick Settings pipeline to log + * the list of current tiles. + */ + @Provides + @SysUISingleton + @QSTileListLog + fun provideQSTileListLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create(QSPipelineLogger.TILE_LIST_TAG, maxSize = 700, systrace = false) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSTileListLog.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSTileListLog.kt new file mode 100644 index 000000000000..ad8bfeabc676 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSTileListLog.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.pipeline.dagger + +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy +import javax.inject.Qualifier + +/** A {@link LogBuffer} for the new QS Pipeline for logging changes to the set of current tiles. */ +@Qualifier @MustBeDocumented @Retention(RetentionPolicy.RUNTIME) annotation class QSTileListLog diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt new file mode 100644 index 000000000000..d254e1b3d0d7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.data.repository + +import android.annotation.UserIdInt +import android.content.res.Resources +import android.database.ContentObserver +import android.provider.Settings +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.qs.QSHost +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.util.settings.SecureSettings +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.withContext + +/** Repository that tracks the current tiles. */ +interface TileSpecRepository { + + /** + * Returns a flow of the current list of [TileSpec] for a given [userId]. + * + * Tiles will never be [TileSpec.Invalid] in the list and it will never be empty. + */ + fun tilesSpecs(@UserIdInt userId: Int): Flow<List<TileSpec>> + + /** + * Adds a [tile] for a given [userId] at [position]. Using [POSITION_AT_END] will add the tile + * at the end of the list. + * + * Passing [TileSpec.Invalid] is a noop. + */ + suspend fun addTile(@UserIdInt userId: Int, tile: TileSpec, position: Int = POSITION_AT_END) + + /** + * Removes a [tile] for a given [userId]. + * + * Passing [TileSpec.Invalid] or a non present tile is a noop. + */ + suspend fun removeTile(@UserIdInt userId: Int, tile: TileSpec) + + /** + * Sets the list of current [tiles] for a given [userId]. + * + * [TileSpec.Invalid] will be ignored, and an effectively empty list will not be stored. + */ + suspend fun setTiles(@UserIdInt userId: Int, tiles: List<TileSpec>) + + companion object { + /** Position to indicate the end of the list */ + const val POSITION_AT_END = -1 + } +} + +/** + * Implementation of [TileSpecRepository] that persist the values of tiles in + * [Settings.Secure.QS_TILES]. + * + * All operations against [Settings] will be performed in a background thread. + */ +@SysUISingleton +class TileSpecSettingsRepository +@Inject +constructor( + private val secureSettings: SecureSettings, + @Main private val resources: Resources, + private val logger: QSPipelineLogger, + @Background private val backgroundDispatcher: CoroutineDispatcher, +) : TileSpecRepository { + override fun tilesSpecs(userId: Int): Flow<List<TileSpec>> { + return conflatedCallbackFlow { + val observer = + object : ContentObserver(null) { + override fun onChange(selfChange: Boolean) { + trySend(Unit) + } + } + + secureSettings.registerContentObserverForUser(SETTING, observer, userId) + + awaitClose { secureSettings.unregisterContentObserver(observer) } + } + .onStart { emit(Unit) } + .map { secureSettings.getStringForUser(SETTING, userId) ?: "" } + .onEach { logger.logTilesChangedInSettings(it, userId) } + .map { parseTileSpecs(it, userId) } + .flowOn(backgroundDispatcher) + } + + override suspend fun addTile(userId: Int, tile: TileSpec, position: Int) { + if (tile == TileSpec.Invalid) { + return + } + val tilesList = loadTiles(userId).toMutableList() + if (tile !in tilesList) { + if (position < 0) { + tilesList.add(tile) + } else { + tilesList.add(position, tile) + } + storeTiles(userId, tilesList) + } + } + + override suspend fun removeTile(userId: Int, tile: TileSpec) { + if (tile == TileSpec.Invalid) { + return + } + val tilesList = loadTiles(userId).toMutableList() + if (tilesList.remove(tile)) { + storeTiles(userId, tilesList.toList()) + } + } + + override suspend fun setTiles(userId: Int, tiles: List<TileSpec>) { + val filtered = tiles.filter { it != TileSpec.Invalid } + if (filtered.isNotEmpty()) { + storeTiles(userId, filtered) + } + } + + private suspend fun loadTiles(@UserIdInt forUser: Int): List<TileSpec> { + return withContext(backgroundDispatcher) { + (secureSettings.getStringForUser(SETTING, forUser) ?: "") + .split(DELIMITER) + .map(TileSpec::create) + .filter { it !is TileSpec.Invalid } + } + } + + private suspend fun storeTiles(@UserIdInt forUser: Int, tiles: List<TileSpec>) { + val toStore = + tiles + .filter { it !is TileSpec.Invalid } + .joinToString(DELIMITER, transform = TileSpec::spec) + withContext(backgroundDispatcher) { + secureSettings.putStringForUser( + SETTING, + toStore, + null, + false, + forUser, + true, + ) + } + } + + private fun parseTileSpecs(tilesFromSettings: String, user: Int): List<TileSpec> { + val fromSettings = + tilesFromSettings.split(DELIMITER).map(TileSpec::create).filter { + it != TileSpec.Invalid + } + return if (fromSettings.isNotEmpty()) { + fromSettings.also { logger.logParsedTiles(it, false, user) } + } else { + QSHost.getDefaultSpecs(resources) + .map(TileSpec::create) + .filter { it != TileSpec.Invalid } + .also { logger.logParsedTiles(it, true, user) } + } + } + + companion object { + private const val SETTING = Settings.Secure.QS_TILES + private const val DELIMITER = "," + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt new file mode 100644 index 000000000000..69d8248a11f5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.prototyping + +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.statusbar.commandline.Command +import com.android.systemui.statusbar.commandline.CommandRegistry +import com.android.systemui.user.data.repository.UserRepository +import java.io.PrintWriter +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.launch + +/** + * Class for observing results while prototyping. + * + * The flows do their own logging, so we just need to make sure that they collect. + * + * This will be torn down together with the last of the new pipeline flags remaining here. + */ +// TODO(b/270385608) +@SysUISingleton +class PrototypeCoreStartable +@Inject +constructor( + private val tileSpecRepository: TileSpecRepository, + private val userRepository: UserRepository, + private val featureFlags: FeatureFlags, + @Application private val scope: CoroutineScope, + private val commandRegistry: CommandRegistry, +) : CoreStartable { + + @OptIn(ExperimentalCoroutinesApi::class) + override fun start() { + if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) { + scope.launch { + userRepository.selectedUserInfo + .flatMapLatest { user -> tileSpecRepository.tilesSpecs(user.id) } + .collect {} + } + commandRegistry.registerCommand(COMMAND, ::CommandExecutor) + } + } + + private inner class CommandExecutor : Command { + override fun execute(pw: PrintWriter, args: List<String>) { + if (args.size < 2) { + pw.println("Error: needs at least two arguments") + return + } + val spec = TileSpec.create(args[1]) + if (spec == TileSpec.Invalid) { + pw.println("Error: Invalid tile spec ${args[1]}") + } + if (args[0] == "add") { + performAdd(args, spec) + pw.println("Requested tile added") + } else if (args[0] == "remove") { + performRemove(args, spec) + pw.println("Requested tile removed") + } else { + pw.println("Error: unknown command") + } + } + + private fun performAdd(args: List<String>, spec: TileSpec) { + val position = args.getOrNull(2)?.toInt() ?: TileSpecRepository.POSITION_AT_END + val user = args.getOrNull(3)?.toInt() ?: userRepository.getSelectedUserInfo().id + scope.launch { tileSpecRepository.addTile(user, spec, position) } + } + + private fun performRemove(args: List<String>, spec: TileSpec) { + val user = args.getOrNull(2)?.toInt() ?: userRepository.getSelectedUserInfo().id + scope.launch { tileSpecRepository.removeTile(user, spec) } + } + + override fun help(pw: PrintWriter) { + pw.println("Usage: adb shell cmd statusbar $COMMAND:") + pw.println(" add <spec> [position] [user]") + pw.println(" remove <spec> [user]") + } + } + + companion object { + private const val COMMAND = "qs-pipeline" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt new file mode 100644 index 000000000000..c691c2f668ad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.shared + +import android.content.ComponentName +import android.text.TextUtils +import com.android.systemui.qs.external.CustomTile + +/** + * Container for the spec that identifies a tile. + * + * A tile's [spec] is one of two options: + * * `custom(<componentName>)`: A [ComponentName] surrounded by [CustomTile.PREFIX] and terminated + * by `)`, represents a tile provided by an app, corresponding to a `TileService`. + * * a string not starting with [CustomTile.PREFIX], representing a tile provided by SystemUI. + */ +sealed class TileSpec private constructor(open val spec: String) { + + /** Represents a spec that couldn't be parsed into a valid type of tile. */ + object Invalid : TileSpec("") { + override fun toString(): String { + return "TileSpec.INVALID" + } + } + + /** Container for the spec of a tile provided by SystemUI. */ + data class PlatformTileSpec + internal constructor( + override val spec: String, + ) : TileSpec(spec) + + /** + * Container for the spec of a tile provided by an app. + * + * [componentName] indicates the associated `TileService`. + */ + data class CustomTileSpec + internal constructor( + override val spec: String, + val componentName: ComponentName, + ) : TileSpec(spec) + + companion object { + /** Create a [TileSpec] from the string [spec]. */ + fun create(spec: String): TileSpec { + return if (TextUtils.isEmpty(spec)) { + Invalid + } else if (!spec.isCustomTileSpec) { + PlatformTileSpec(spec) + } else { + spec.componentName?.let { CustomTileSpec(spec, it) } ?: Invalid + } + } + + private val String.isCustomTileSpec: Boolean + get() = startsWith(CustomTile.PREFIX) + + private val String.componentName: ComponentName? + get() = + if (!isCustomTileSpec) { + null + } else { + if (endsWith(")")) { + val extracted = substring(CustomTile.PREFIX.length, length - 1) + ComponentName.unflattenFromString(extracted) + } else { + null + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt new file mode 100644 index 000000000000..200f7431e906 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.shared.logging + +import android.annotation.UserIdInt +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.qs.pipeline.dagger.QSTileListLog +import com.android.systemui.qs.pipeline.shared.TileSpec +import javax.inject.Inject + +/** + * Logger for the new pipeline. + * + * This may log to different buffers depending of the function of the log. + */ +class QSPipelineLogger +@Inject +constructor( + @QSTileListLog private val tileListLogBuffer: LogBuffer, +) { + + companion object { + const val TILE_LIST_TAG = "QSTileListLog" + } + + /** + * Log the tiles that are parsed in the repo. This is effectively what is surfaces in the flow. + * + * [usesDefault] indicates if the default tiles were used (due to the setting being empty or + * invalid). + */ + fun logParsedTiles(tiles: List<TileSpec>, usesDefault: Boolean, user: Int) { + tileListLogBuffer.log( + TILE_LIST_TAG, + LogLevel.DEBUG, + { + str1 = tiles.toString() + bool1 = usesDefault + int1 = user + }, + { "Parsed tiles (default=$bool1, user=$int1): $str1" } + ) + } + + /** + * Logs when the tiles change in Settings. + * + * This could be caused by SystemUI, or restore. + */ + fun logTilesChangedInSettings(newTiles: String, @UserIdInt user: Int) { + tileListLogBuffer.log( + TILE_LIST_TAG, + LogLevel.VERBOSE, + { + str1 = newTiles + int1 = user + }, + { "Tiles changed in settings for user $int1: $str1" } + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 80eea81a541d..1b83397b1afb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -788,7 +788,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private void disconnectFromLauncherService(String disconnectReason) { Log.d(TAG_OPS, "disconnectFromLauncherService bound?: " + mBound + - " currentProxy: " + mOverviewProxy + " disconnectReason: " + disconnectReason); + " currentProxy: " + mOverviewProxy + " disconnectReason: " + disconnectReason, + new Throwable()); if (mBound) { // Always unbind the service (ie. if called through onNullBinding or onBindingDied) mContext.unbindService(mOverviewServiceConnection); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index efd79d737f71..3227ef47f733 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -190,9 +190,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { } catch (Exception e) { // IOException/UnsupportedOperationException may be thrown if external storage is // not mounted - if (DEBUG_STORAGE) { - Log.d(TAG, "Failed to store screenshot", e); - } + Log.d(TAG, "Failed to store screenshot", e); mParams.clearImage(); mImageData.reset(); mQuickShareData.reset(); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index b2ae4a021f2c..a9af1a2457f9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -488,10 +488,6 @@ public class ScreenshotController { }); } - if (DEBUG_WINDOW) { - Log.d(TAG, "setContentView: " + mScreenshotView); - } - setContentView(mScreenshotView); // ignore system bar insets for the purpose of window layout mWindow.getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> WindowInsets.CONSUMED); @@ -790,10 +786,6 @@ public class ScreenshotController { mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon( mContext.getDrawable(R.drawable.overlay_badge_background), owner)); mScreenshotView.setScreenshot(mScreenBitmap, screenInsets); - if (DEBUG_WINDOW) { - Log.d(TAG, "setContentView: " + mScreenshotView); - } - setContentView(mScreenshotView); // ignore system bar insets for the purpose of window layout mWindow.getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> WindowInsets.CONSUMED); @@ -1119,9 +1111,7 @@ public class ScreenshotController { /** Reset screenshot view and then call onCompleteRunnable */ private void finishDismiss() { - if (DEBUG_DISMISS) { - Log.d(TAG, "finishDismiss"); - } + Log.d(TAG, "finishDismiss"); if (mLastScrollCaptureRequest != null) { mLastScrollCaptureRequest.cancel(true); mLastScrollCaptureRequest = null; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java index 7ac0fd50ea33..f3d2828072be 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java @@ -253,6 +253,7 @@ public class TakeScreenshotService extends Service { Consumer<Uri> uriConsumer, RequestCallback callback) { mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshot.getSource()), 0, screenshot.getPackageNameString()); + Log.d(TAG, "Screenshot request: " + screenshot); mScreenshot.handleScreenshot(screenshot, uriConsumer, callback); } diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index 0b2ae05b7c9b..72286f175671 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -161,6 +161,10 @@ open class UserTrackerImpl internal constructor( private fun registerUserSwitchObserver() { iActivityManager.registerUserSwitchObserver(object : UserSwitchObserver() { + override fun onBeforeUserSwitching(newUserId: Int) { + setUserIdInternal(newUserId) + } + override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) { backgroundHandler.run { handleUserSwitching(newUserId) @@ -181,8 +185,6 @@ open class UserTrackerImpl internal constructor( Assert.isNotMainThread() Log.i(TAG, "Switching to user $newUserId") - setUserIdInternal(newUserId) - val list = synchronized(callbacks) { callbacks.toList() } @@ -205,7 +207,6 @@ open class UserTrackerImpl internal constructor( Assert.isNotMainThread() Log.i(TAG, "Switched to user $newUserId") - setUserIdInternal(newUserId) notifySubscribers { onUserChanged(newUserId, userContext) onProfilesChanged(userProfiles) diff --git a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java index fb2ddc15bab1..233667335b72 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java @@ -93,7 +93,7 @@ public class DebugDrawable extends Drawable { drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY, "mLockIconViewController.getTop()"); - if (mNotificationPanelViewController.getKeyguardShowing()) { + if (mNotificationPanelViewController.isKeyguardShowing()) { // Notifications have the space between those two lines. drawDebugInfo(canvas, mNotificationStackScrollLayoutController.getTop() diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 636058bd9717..7b4685216111 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -249,13 +249,14 @@ import javax.inject.Provider; import kotlinx.coroutines.CoroutineDispatcher; @CentralSurfacesComponent.CentralSurfacesScope -public final class NotificationPanelViewController implements Dumpable { +public final class NotificationPanelViewController implements ShadeSurface, Dumpable { public static final String TAG = NotificationPanelView.class.getSimpleName(); public static final float FLING_MAX_LENGTH_SECONDS = 0.6f; public static final float FLING_SPEED_UP_FACTOR = 0.6f; public static final float FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f; public static final float FLING_CLOSING_SPEED_UP_FACTOR = 0.6f; + public static final int WAKEUP_ANIMATION_DELAY_MS = 250; private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG); private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE); private static final boolean DEBUG_DRAWABLE = false; @@ -278,6 +279,7 @@ public final class NotificationPanelViewController implements Dumpable { private static final int NO_FIXED_DURATION = -1; private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L; private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L; + /** * The factor of the usual high velocity that is needed in order to reach the maximum overshoot * when flinging. A low value will make it that most flings will reach the maximum overshoot. @@ -389,7 +391,6 @@ public final class NotificationPanelViewController implements Dumpable { private KeyguardBottomAreaView mKeyguardBottomArea; private boolean mExpanding; private boolean mSplitShadeEnabled; - private final boolean mMultiShadeEnabled; /** The bottom padding reserved for elements of the keyguard measuring notifications. */ private float mKeyguardNotificationBottomPadding; /** @@ -441,8 +442,6 @@ public final class NotificationPanelViewController implements Dumpable { new KeyguardClockPositionAlgorithm.Result(); private boolean mIsExpanding; - private String mHeaderDebugInfo; - /** * Indicates drag starting height when swiping down or up on heads-up notifications. * This usually serves as a threshold from when shade expansion should really start. Otherwise @@ -458,6 +457,10 @@ public final class NotificationPanelViewController implements Dumpable { private boolean mHeadsUpAnimatingAway; private final FalsingManager mFalsingManager; private final FalsingCollector mFalsingCollector; + private final ShadeHeadsUpTrackerImpl mShadeHeadsUpTracker = new ShadeHeadsUpTrackerImpl(); + private final ShadeFoldAnimator mShadeFoldAnimator = new ShadeFoldAnimatorImpl(); + private final ShadeNotificationPresenterImpl mShadeNotificationPresenter = + new ShadeNotificationPresenterImpl(); private boolean mShowIconsWhenExpanded; private int mIndicationBottomPadding; @@ -561,7 +564,6 @@ public final class NotificationPanelViewController implements Dumpable { private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel; private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; private float mMinExpandHeight; - private final ShadeHeightLogger mShadeHeightLogger; private boolean mPanelUpdateWhenAnimatorEnds; private boolean mHasVibratedOnOpen = false; private int mFixedDuration = NO_FIXED_DURATION; @@ -606,6 +608,12 @@ public final class NotificationPanelViewController implements Dumpable { private boolean mGestureWaitForTouchSlop; private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; + /** + * Whether we're waking up and will play the delayed doze animation in + * {@link NotificationWakeUpCoordinator}. If so, we'll want to keep the clock centered until the + * delayed doze animation starts. + */ + private boolean mWillPlayDelayedDozeAmountAnimation = false; private final DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel; private final OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel; private final LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel; @@ -628,7 +636,7 @@ public final class NotificationPanelViewController implements Dumpable { () -> mKeyguardBottomArea.setVisibility(View.GONE); private final Runnable mHeadsUpExistenceChangedRunnable = () -> { setHeadsUpAnimatingAway(false); - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); }; private final Runnable mMaybeHideExpandedRunnable = () -> { if (getExpandedFraction() == 0.0f) { @@ -699,7 +707,6 @@ public final class NotificationPanelViewController implements Dumpable { KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger, ShadeLogger shadeLogger, - ShadeHeightLogger shadeHeightLogger, ConfigurationController configurationController, Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder, StatusBarTouchableRegionManager statusBarTouchableRegionManager, @@ -769,7 +776,6 @@ public final class NotificationPanelViewController implements Dumpable { mLockscreenGestureLogger = lockscreenGestureLogger; mShadeExpansionStateManager = shadeExpansionStateManager; mShadeLog = shadeLogger; - mShadeHeightLogger = shadeHeightLogger; mGutsManager = gutsManager; mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel; mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel; @@ -854,14 +860,13 @@ public final class NotificationPanelViewController implements Dumpable { mFeatureFlags = featureFlags; mAnimateBack = mFeatureFlags.isEnabled(Flags.WM_SHADE_ANIMATE_BACK_GESTURE); mTrackpadGestureBack = mFeatureFlags.isEnabled(Flags.TRACKPAD_GESTURE_FEATURES); - mMultiShadeEnabled = mFeatureFlags.isEnabled(Flags.DUAL_SHADE); mFalsingCollector = falsingCollector; mPowerManager = powerManager; mWakeUpCoordinator = coordinator; mMainDispatcher = mainDispatcher; mAccessibilityManager = accessibilityManager; mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); - setPanelAlpha(255, false /* animate */); + setAlpha(255, false /* animate */); mCommandQueue = commandQueue; mDisplayId = displayId; mPulseExpansionHandler = pulseExpansionHandler; @@ -1045,7 +1050,8 @@ public final class NotificationPanelViewController implements Dumpable { mOnEmptySpaceClickListener); mQsController.initNotificationStackScrollLayoutController(); mShadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged); - addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp); + mShadeHeadsUpTracker.addTrackingHeadsUpListener( + mNotificationStackScrollLayoutController::setTrackingHeadsUp); setKeyguardBottomArea(mView.findViewById(R.id.keyguard_bottom_area)); initBottomArea(); @@ -1065,6 +1071,12 @@ public final class NotificationPanelViewController implements Dumpable { requestScrollerTopPaddingUpdate(false /* animate */); } } + + @Override + public void onDelayedDozeAmountAnimationRunning(boolean running) { + // On running OR finished, the animation is no longer waiting to play + setWillPlayDelayedDozeAmountAnimation(false); + } }); mView.setRtlChangeListener(layoutDirection -> { @@ -1205,6 +1217,7 @@ public final class NotificationPanelViewController implements Dumpable { } } + @Override public void updateResources() { final boolean newSplitShadeEnabled = LargeScreenUtils.shouldUseSplitNotificationShade(mResources); @@ -1385,7 +1398,7 @@ public final class NotificationPanelViewController implements Dumpable { if (SPEW_LOGCAT) Log.d(TAG, "Skipping computeMaxKeyguardNotifications() by request"); } - if (getKeyguardShowing() && !mKeyguardBypassController.getBypassEnabled()) { + if (isKeyguardShowing() && !mKeyguardBypassController.getBypassEnabled()) { mNotificationStackScrollLayoutController.setMaxDisplayedNotifications( mMaxAllowedKeyguardNotifications); mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug( @@ -1546,7 +1559,7 @@ public final class NotificationPanelViewController implements Dumpable { updateClock(); } - public KeyguardClockPositionAlgorithm.Result getClockPositionResult() { + KeyguardClockPositionAlgorithm.Result getClockPositionResult() { return mClockPositionResult; } @@ -1657,15 +1670,32 @@ public final class NotificationPanelViewController implements Dumpable { // overlap. return true; } - if (hasPulsingNotifications()) { + if (mNotificationListContainer.hasPulsingNotifications()) { // Pulsing notification appears on the right. Move clock left to avoid overlap. return false; } + if (mWillPlayDelayedDozeAmountAnimation) { + return true; + } // "Visible" notifications are actually not visible on AOD (unless pulsing), so it is safe // to center the clock without overlap. return isOnAod(); } + /** + * Notify us that {@link NotificationWakeUpCoordinator} is going to play the doze wakeup + * animation after a delay. If so, we'll keep the clock centered until that animation starts. + */ + public void setWillPlayDelayedDozeAmountAnimation(boolean willPlay) { + if (mWillPlayDelayedDozeAmountAnimation == willPlay) return; + + mWillPlayDelayedDozeAmountAnimation = willPlay; + mWakeUpCoordinator.logDelayingClockWakeUpAnimation(willPlay); + + // Once changing this value, see if we should move the clock. + positionClockAndNotifications(); + } + private boolean isOnAod() { return mDozing && mDozeParameters.getAlwaysOn(); } @@ -1787,27 +1817,28 @@ public final class NotificationPanelViewController implements Dumpable { } } - public void animateToFullShade(long delay) { + @Override + public void transitionToExpandedShade(long delay) { mNotificationStackScrollLayoutController.goToFullShade(delay); mView.requestLayout(); mAnimateNextPositionUpdate = true; } - /** Animate QS closing. */ - public void animateCloseQs(boolean animateAway) { + @Override + public void animateCollapseQs(boolean fullyCollapse) { if (mSplitShadeEnabled) { - collapsePanel(true, false, 1.0f); + collapse(true, false, 1.0f); } else { - mQsController.animateCloseQs(animateAway); + mQsController.animateCloseQs(fullyCollapse); } - } + @Override public void resetViews(boolean animate) { mGutsManager.closeAndSaveGuts(true /* leavebehind */, true /* force */, true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */); if (animate && !isFullyCollapsed()) { - animateCloseQs(true); + animateCollapseQs(true); } else { closeQsIfPossible(); } @@ -1816,15 +1847,14 @@ public final class NotificationPanelViewController implements Dumpable { mNotificationStackScrollLayoutController.resetScrollPosition(); } - /** Collapses the panel. */ - public void collapsePanel(boolean animate, boolean delayed, float speedUpFactor) { + @Override + public void collapse(boolean animate, boolean delayed, float speedUpFactor) { boolean waiting = false; if (animate && !isFullyCollapsed()) { collapse(delayed, speedUpFactor); waiting = true; } else { resetViews(false /* animate */); - mShadeHeightLogger.logFunctionCall("collapsePanel"); setExpandedFraction(0); // just in case } if (!waiting) { @@ -1835,8 +1865,9 @@ public final class NotificationPanelViewController implements Dumpable { } } + @Override public void collapse(boolean delayed, float speedUpFactor) { - if (!canPanelBeCollapsed()) { + if (!canBeCollapsed()) { return; } @@ -1845,7 +1876,7 @@ public final class NotificationPanelViewController implements Dumpable { setShowShelfOnly(true); } debugLog("collapse: %s", this); - if (canPanelBeCollapsed()) { + if (canBeCollapsed()) { cancelHeightAnimator(); notifyExpandingStarted(); @@ -1876,11 +1907,13 @@ public final class NotificationPanelViewController implements Dumpable { endClosing(); } + @Override public void cancelAnimation() { mView.animate().cancel(); } - public void expandWithQs() { + @Override + public void expandToQs() { if (mQsController.isExpansionEnabled()) { mQsController.setExpandImmediate(true); setShowShelfOnly(true); @@ -1903,15 +1936,9 @@ public final class NotificationPanelViewController implements Dumpable { } } - /** - * Expand shade so that notifications are visible. - * Non-split shade: just expanding shade or collapsing QS when they're expanded. - * Split shade: only expanding shade, notifications are always visible - * - * Called when `adb shell cmd statusbar expand-notifications` is executed. - */ - public void expandShadeToNotifications() { - if (mSplitShadeEnabled && (isShadeFullyOpen() || isExpanding())) { + @Override + public void expandToNotifications() { + if (mSplitShadeEnabled && (isShadeFullyExpanded() || isExpanding())) { return; } if (mQsController.getExpanded()) { @@ -2048,7 +2075,7 @@ public final class NotificationPanelViewController implements Dumpable { } else { mQsController.cancelJankMonitoring(); } - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); mNotificationStackScrollLayoutController.setPanelFlinging(false); } @@ -2122,12 +2149,12 @@ public final class NotificationPanelViewController implements Dumpable { } /** Return whether a touch is near the gesture handle at the bottom of screen */ - public boolean isInGestureNavHomeHandleArea(float x, float y) { + boolean isInGestureNavHomeHandleArea(float x, float y) { return mIsGestureNavigation && y > mView.getHeight() - mNavigationBarBottomHeight; } - /** Input focus transfer is about to happen. */ - public void startWaitingForOpenPanelGesture() { + @Override + public void startWaitingForExpandGesture() { if (!isFullyCollapsed()) { return; } @@ -2136,21 +2163,8 @@ public final class NotificationPanelViewController implements Dumpable { updatePanelExpanded(); } - /** - * Called when this view is no longer waiting for input focus transfer. - * - * There are two scenarios behind this function call. First, input focus transfer - * has successfully happened and this view already received synthetic DOWN event. - * (mExpectingSynthesizedDown == false). Do nothing. - * - * Second, before input focus transfer finished, user may have lifted finger - * in previous window and this window never received synthetic DOWN event. - * (mExpectingSynthesizedDown == true). - * In this case, we use the velocity to trigger fling event. - * - * @param velocity unit is in px / millis - */ - public void stopWaitingForOpenPanelGesture(boolean cancel, final float velocity) { + @Override + public void stopWaitingForExpandGesture(boolean cancel, final float velocity) { if (mExpectingSynthesizedDown) { mExpectingSynthesizedDown = false; if (cancel) { @@ -2235,7 +2249,7 @@ public final class NotificationPanelViewController implements Dumpable { * as the shade ends up in its half-expanded state (with QQS above), it is back at 100% scale. * Without this, the shade would collapse, and stay squished. */ - public void adjustBackAnimationScale(float expansionFraction) { + void adjustBackAnimationScale(float expansionFraction) { if (expansionFraction > 0.0f) { // collapsing float animatedFraction = expansionFraction * mCurrentBackProgress; applyBackScaling(animatedFraction); @@ -2246,11 +2260,12 @@ public final class NotificationPanelViewController implements Dumpable { } //TODO(b/270981268): allow cancelling back animation mid-flight - /** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */ + @Override public void onBackPressed() { closeQsIfPossible(); } - /** Sets back progress. */ + + @Override public void onBackProgressed(float progressFraction) { // TODO: non-linearly transform progress fraction into squish amount (ease-in, linear out) mCurrentBackProgress = progressFraction; @@ -2258,16 +2273,17 @@ public final class NotificationPanelViewController implements Dumpable { } /** Resets back progress. */ - public void resetBackTransformation() { + private void resetBackTransformation() { mCurrentBackProgress = 0.0f; applyBackScaling(0.0f); } - /** Scales multiple elements in tandem to achieve the illusion of the QS+Shade shrinking - * as a single visual element (used by the Predictive Back Gesture preview animation). - * fraction = 0 implies "no scaling", and 1 means "scale down to minimum size (90%)". + /** + * Scales multiple elements in tandem to achieve the illusion of the QS+Shade shrinking + * as a single visual element (used by the Predictive Back Gesture preview animation). + * fraction = 0 implies "no scaling", and 1 means "scale down to minimum size (90%)". */ - public void applyBackScaling(float fraction) { + private void applyBackScaling(float fraction) { if (mNotificationContainerParent == null) { return; } @@ -2275,15 +2291,6 @@ public final class NotificationPanelViewController implements Dumpable { mNotificationContainerParent.applyBackScaling(scale, mSplitShadeEnabled); mScrimController.applyBackScaling(scale); } - /** */ - public float getLockscreenShadeDragProgress() { - // mTransitioningToFullShadeProgress > 0 means we're doing regular lockscreen to shade - // transition. If that's not the case we should follow QS expansion fraction for when - // user is pulling from the same top to go directly to expanded QS - return mQsController.getTransitioningToFullShadeProgress() > 0 - ? mLockscreenShadeTransitionController.getQSDragProgress() - : mQsController.computeExpansionFraction(); - } String determineAccessibilityPaneTitle() { if (mQsController != null && mQsController.isCustomizing()) { @@ -2306,8 +2313,8 @@ public final class NotificationPanelViewController implements Dumpable { } /** Returns the topPadding of notifications when on keyguard not respecting QS expansion. */ - public int getKeyguardNotificationStaticPadding() { - if (!getKeyguardShowing()) { + int getKeyguardNotificationStaticPadding() { + if (!isKeyguardShowing()) { return 0; } if (!mKeyguardBypassController.getBypassEnabled()) { @@ -2324,15 +2331,15 @@ public final class NotificationPanelViewController implements Dumpable { } } - public boolean getKeyguardShowing() { + boolean isKeyguardShowing() { return mBarState == KEYGUARD; } - public float getKeyguardNotificationTopPadding() { + float getKeyguardNotificationTopPadding() { return mKeyguardNotificationTopPadding; } - public float getKeyguardNotificationBottomPadding() { + float getKeyguardNotificationBottomPadding() { return mKeyguardNotificationBottomPadding; } @@ -2340,17 +2347,14 @@ public final class NotificationPanelViewController implements Dumpable { mNotificationStackScrollLayoutController.updateTopPadding( mQsController.calculateNotificationsTopPadding(mIsExpanding, getKeyguardNotificationStaticPadding(), mExpandedFraction), animate); - if (getKeyguardShowing() + if (isKeyguardShowing() && mKeyguardBypassController.getBypassEnabled()) { // update the position of the header mQsController.updateExpansion(); } } - /** - * Set the alpha and translationY of the keyguard elements which only show on the lockscreen, - * but not in shade locked / shade. This is used when dragging down to the full shade. - */ + @Override public void setKeyguardTransitionProgress(float keyguardAlpha, int keyguardTranslationY) { mKeyguardOnlyContentAlpha = Interpolators.ALPHA_IN.getInterpolation(keyguardAlpha); mKeyguardOnlyTransitionTranslationY = keyguardTranslationY; @@ -2362,17 +2366,13 @@ public final class NotificationPanelViewController implements Dumpable { updateClock(); } - /** - * Sets the alpha value to be set on the keyguard status bar. - * - * @param alpha value between 0 and 1. -1 if the value is to be reset. - */ + @Override public void setKeyguardStatusBarAlpha(float alpha) { mKeyguardStatusBarViewController.setAlpha(alpha); } /** */ - public float getKeyguardOnlyContentAlpha() { + float getKeyguardOnlyContentAlpha() { return mKeyguardOnlyContentAlpha; } @@ -2453,7 +2453,7 @@ public final class NotificationPanelViewController implements Dumpable { float qsExpansionFraction; if (mSplitShadeEnabled) { qsExpansionFraction = 1; - } else if (getKeyguardShowing()) { + } else if (isKeyguardShowing()) { // On Keyguard, interpolate the QS expansion linearly to the panel expansion qsExpansionFraction = expandedHeight / (getMaxPanelHeight()); } else { @@ -2590,31 +2590,19 @@ public final class NotificationPanelViewController implements Dumpable { } setShowShelfOnly(false); mQsController.setTwoFingerExpandPossible(false); - updateTrackingHeadsUp(null); + mShadeHeadsUpTracker.updateTrackingHeadsUp(null); mExpandingFromHeadsUp = false; setPanelScrimMinFraction(0.0f); // Reset status bar alpha so alpha can be calculated upon updating view state. setKeyguardStatusBarAlpha(-1f); } - private void updateTrackingHeadsUp(@Nullable ExpandableNotificationRow pickedChild) { - mTrackedHeadsUpNotification = pickedChild; - for (int i = 0; i < mTrackingHeadsUpListeners.size(); i++) { - Consumer<ExpandableNotificationRow> listener = mTrackingHeadsUpListeners.get(i); - listener.accept(pickedChild); - } - } - - @Nullable - public ExpandableNotificationRow getTrackedHeadsUpNotification() { - return mTrackedHeadsUpNotification; - } - private void setListening(boolean listening) { mKeyguardStatusBarViewController.setBatteryListening(listening); mQsController.setListening(listening); } + @Override public void expand(boolean animate) { if (isFullyCollapsed() || isCollapsing()) { mInstantExpanding = true; @@ -2628,7 +2616,7 @@ public final class NotificationPanelViewController implements Dumpable { if (mExpanding) { notifyExpandingFinished(); } - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); // Wait for window manager to pickup the change, so we know the maximum height of the // panel then. this.mView.getViewTreeObserver().addOnGlobalLayoutListener( @@ -2649,7 +2637,6 @@ public final class NotificationPanelViewController implements Dumpable { mQsController.beginJankMonitoring(isFullyCollapsed()); fling(0 /* expand */); } else { - mShadeHeightLogger.logFunctionCall("expand"); setExpandedFraction(1f); } mInstantExpanding = false; @@ -2668,7 +2655,8 @@ public final class NotificationPanelViewController implements Dumpable { mTouchSlopExceeded = isTouchSlopExceeded; } - public void setOverExpansion(float overExpansion) { + @VisibleForTesting + void setOverExpansion(float overExpansion) { if (overExpansion == mOverExpansion) { return; } @@ -2708,20 +2696,20 @@ public final class NotificationPanelViewController implements Dumpable { mTracking = true; mTrackingStartedListener.onTrackingStarted(); notifyExpandingStarted(); - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); mScrimController.onTrackingStarted(); if (mQsController.getFullyExpanded()) { mQsController.setExpandImmediate(true); setShowShelfOnly(true); } mNotificationStackScrollLayoutController.onPanelTrackingStarted(); - cancelPendingPanelCollapse(); + cancelPendingCollapse(); } private void onTrackingStopped(boolean expand) { mFalsingCollector.onTrackingStopped(); mTracking = false; - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); if (expand) { mNotificationStackScrollLayoutController.setOverScrollAmount(0.0f, true /* onTop */, true /* animate */); @@ -2807,6 +2795,7 @@ public final class NotificationPanelViewController implements Dumpable { } } + @Override public void setIsLaunchAnimationRunning(boolean running) { boolean wasRunning = mIsLaunchAnimationRunning; mIsLaunchAnimationRunning = running; @@ -2831,6 +2820,7 @@ public final class NotificationPanelViewController implements Dumpable { } } + @Override public void onScreenTurningOn() { mKeyguardStatusViewController.dozeTimeTick(); } @@ -2866,7 +2856,8 @@ public final class NotificationPanelViewController implements Dumpable { } } - public void setPanelAlpha(int alpha, boolean animate) { + @Override + public void setAlpha(int alpha, boolean animate) { if (mPanelAlpha != alpha) { mPanelAlpha = alpha; PropertyAnimator.setProperty(mView, mPanelAlphaAnimator, alpha, alpha == 255 @@ -2875,17 +2866,18 @@ public final class NotificationPanelViewController implements Dumpable { } } - public void setPanelAlphaEndAction(Runnable r) { + @Override + public void setAlphaChangeAnimationEndAction(Runnable r) { mPanelAlphaEndAction = r; } - public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { + private void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { mHeadsUpAnimatingAway = headsUpAnimatingAway; mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway); updateVisibility(); } - /** Set whether the bouncer is showing. */ + @Override public void setBouncerShowing(boolean bouncerShowing) { mBouncerShowing = bouncerShowing; updateVisibility(); @@ -2896,7 +2888,7 @@ public final class NotificationPanelViewController implements Dumpable { return headsUpVisible || isExpanded() || mBouncerShowing; } - public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) { + private void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) { mHeadsUpManager = headsUpManager; mHeadsUpManager.addListener(mOnHeadsUpChangedListener); mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, @@ -2940,6 +2932,7 @@ public final class NotificationPanelViewController implements Dumpable { } } + @Override public int getBarState() { return mBarState; } @@ -2989,7 +2982,8 @@ public final class NotificationPanelViewController implements Dumpable { && mBarState == StatusBarState.SHADE; } - public boolean hideStatusBarIconsWhenExpanded() { + @Override + public boolean shouldHideStatusBarIconsWhenExpanded() { if (mIsLaunchAnimationRunning) { return mHideIconsDuringLaunchAnimation; } @@ -3000,6 +2994,7 @@ public final class NotificationPanelViewController implements Dumpable { return !mShowIconsWhenExpanded; } + @Override public void setTouchAndAnimationDisabled(boolean disabled) { mTouchDisabled = disabled; if (mTouchDisabled) { @@ -3012,12 +3007,7 @@ public final class NotificationPanelViewController implements Dumpable { mNotificationStackScrollLayoutController.setAnimationsEnabled(!disabled); } - /** - * Sets the dozing state. - * - * @param dozing {@code true} when dozing. - * @param animate if transition should be animated. - */ + @Override public void setDozing(boolean dozing, boolean animate) { if (dozing == mDozing) return; mView.setDozing(dozing); @@ -3042,6 +3032,7 @@ public final class NotificationPanelViewController implements Dumpable { updateKeyguardStatusViewAlignment(animate); } + @Override public void setPulsing(boolean pulsing) { mPulsing = pulsing; final boolean @@ -3060,6 +3051,7 @@ public final class NotificationPanelViewController implements Dumpable { updateKeyguardStatusViewAlignment(/* animate= */ true); } + @Override public void setAmbientIndicationTop(int ambientIndicationTop, boolean ambientTextVisible) { int ambientIndicationBottomPadding = 0; if (ambientTextVisible) { @@ -3072,6 +3064,7 @@ public final class NotificationPanelViewController implements Dumpable { } } + @Override public void dozeTimeTick() { mLockIconViewController.dozeTimeTick(); mKeyguardStatusViewController.dozeTimeTick(); @@ -3080,15 +3073,17 @@ public final class NotificationPanelViewController implements Dumpable { } } - public void setStatusAccessibilityImportance(int mode) { + void setStatusAccessibilityImportance(int mode) { mKeyguardStatusViewController.setStatusAccessibilityImportance(mode); } //TODO(b/254875405): this should be removed. + @Override public KeyguardBottomAreaView getKeyguardBottomAreaView() { return mKeyguardBottomArea; } + @Override public void applyLaunchAnimationProgress(float linearProgress) { boolean hideIcons = LaunchAnimator.getProgress(ActivityLaunchAnimator.TIMINGS, linearProgress, ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f; @@ -3100,20 +3095,43 @@ public final class NotificationPanelViewController implements Dumpable { } } - public void addTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) { - mTrackingHeadsUpListeners.add(listener); - } + private class ShadeHeadsUpTrackerImpl implements ShadeHeadsUpTracker { + @Override + public void addTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) { + mTrackingHeadsUpListeners.add(listener); + } + + @Override + public void removeTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) { + mTrackingHeadsUpListeners.remove(listener); + } + + @Override + public void setHeadsUpAppearanceController( + HeadsUpAppearanceController headsUpAppearanceController) { + mHeadsUpAppearanceController = headsUpAppearanceController; + } + + @Override + @Nullable public ExpandableNotificationRow getTrackedHeadsUpNotification() { + return mTrackedHeadsUpNotification; + } - public void removeTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) { - mTrackingHeadsUpListeners.remove(listener); + private void updateTrackingHeadsUp(@Nullable ExpandableNotificationRow pickedChild) { + mTrackedHeadsUpNotification = pickedChild; + for (int i = 0; i < mTrackingHeadsUpListeners.size(); i++) { + Consumer<ExpandableNotificationRow> listener = mTrackingHeadsUpListeners.get(i); + listener.accept(pickedChild); + } + } } - public void setHeadsUpAppearanceController( - HeadsUpAppearanceController headsUpAppearanceController) { - mHeadsUpAppearanceController = headsUpAppearanceController; + @Override + public ShadeHeadsUpTracker getShadeHeadsUpTracker() { + return mShadeHeadsUpTracker; } - /** Called before animating Keyguard dismissal, i.e. the animation dismissing the bouncer. */ + @Override public void startBouncerPreHideAnimation() { if (mKeyguardQsUserSwitchController != null) { mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility( @@ -3131,74 +3149,90 @@ public final class NotificationPanelViewController implements Dumpable { } } - /** Updates the views to the initial state for the fold to AOD animation. */ - public void prepareFoldToAodAnimation() { - // Force show AOD UI even if we are not locked - showAodUi(); - - // Move the content of the AOD all the way to the left - // so we can animate to the initial position - final int translationAmount = mView.getResources().getDimensionPixelSize( - R.dimen.below_clock_padding_start); - mView.setTranslationX(-translationAmount); - mView.setAlpha(0); + @Override + public ShadeFoldAnimator getShadeFoldAnimator() { + return mShadeFoldAnimator; } - /** - * Starts fold to AOD animation. - * - * @param startAction invoked when the animation starts. - * @param endAction invoked when the animation finishes, also if it was cancelled. - * @param cancelAction invoked when the animation is cancelled, before endAction. - */ - public void startFoldToAodAnimation(Runnable startAction, Runnable endAction, - Runnable cancelAction) { - final ViewPropertyAnimator viewAnimator = mView.animate(); - viewAnimator.cancel(); - viewAnimator - .translationX(0) - .alpha(1f) - .setDuration(ANIMATION_DURATION_FOLD_TO_AOD) - .setInterpolator(EMPHASIZED_DECELERATE) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - startAction.run(); - } + private final class ShadeFoldAnimatorImpl implements ShadeFoldAnimator { + /** Updates the views to the initial state for the fold to AOD animation. */ + @Override + public void prepareFoldToAodAnimation() { + // Force show AOD UI even if we are not locked + showAodUi(); - @Override - public void onAnimationCancel(Animator animation) { - cancelAction.run(); - } + // Move the content of the AOD all the way to the left + // so we can animate to the initial position + final int translationAmount = mView.getResources().getDimensionPixelSize( + R.dimen.below_clock_padding_start); + mView.setTranslationX(-translationAmount); + mView.setAlpha(0); + } - @Override - public void onAnimationEnd(Animator animation) { - endAction.run(); + /** + * Starts fold to AOD animation. + * + * @param startAction invoked when the animation starts. + * @param endAction invoked when the animation finishes, also if it was cancelled. + * @param cancelAction invoked when the animation is cancelled, before endAction. + */ + @Override + public void startFoldToAodAnimation(Runnable startAction, Runnable endAction, + Runnable cancelAction) { + final ViewPropertyAnimator viewAnimator = mView.animate(); + viewAnimator.cancel(); + viewAnimator + .translationX(0) + .alpha(1f) + .setDuration(ANIMATION_DURATION_FOLD_TO_AOD) + .setInterpolator(EMPHASIZED_DECELERATE) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + startAction.run(); + } - viewAnimator.setListener(null); - viewAnimator.setUpdateListener(null); - } - }) - .setUpdateListener(anim -> - mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction())) - .start(); - } + @Override + public void onAnimationCancel(Animator animation) { + cancelAction.run(); + } - /** Cancels fold to AOD transition and resets view state. */ - public void cancelFoldToAodAnimation() { - cancelAnimation(); - resetAlpha(); - resetTranslation(); + @Override + public void onAnimationEnd(Animator animation) { + endAction.run(); + + viewAnimator.setListener(null); + viewAnimator.setUpdateListener(null); + } + }) + .setUpdateListener(anim -> + mKeyguardStatusViewController.animateFoldToAod( + anim.getAnimatedFraction())) + .start(); + } + + /** Cancels fold to AOD transition and resets view state. */ + @Override + public void cancelFoldToAodAnimation() { + cancelAnimation(); + resetAlpha(); + resetTranslation(); + } + + /** Returns the NotificationPanelView. */ + @Override + public ViewGroup getView() { + // TODO(b/254878364): remove this method, or at least reduce references to it. + return mView; + } } + @Override public void setImportantForAccessibility(int mode) { mView.setImportantForAccessibility(mode); } - /** - * Do not let the user drag the shade up and down for the current touch session. - * This is necessary to avoid shade expansion while/after the bouncer is dismissed. - */ + @Override public void blockExpansionForCurrentTouch() { mBlockingExpansionForCurrentTouch = mTracking; } @@ -3240,7 +3274,6 @@ public final class NotificationPanelViewController implements Dumpable { ipw.print("mDisplayRightInset="); ipw.println(mDisplayRightInset); ipw.print("mDisplayLeftInset="); ipw.println(mDisplayLeftInset); ipw.print("mIsExpanding="); ipw.println(mIsExpanding); - ipw.print("mHeaderDebugInfo="); ipw.println(mHeaderDebugInfo); ipw.print("mHeadsUpStartHeight="); ipw.println(mHeadsUpStartHeight); ipw.print("mListenForHeadsUp="); ipw.println(mListenForHeadsUp); ipw.print("mNavigationBarBottomHeight="); ipw.println(mNavigationBarBottomHeight); @@ -3329,37 +3362,41 @@ public final class NotificationPanelViewController implements Dumpable { ).printTableData(ipw); } + private final class ShadeNotificationPresenterImpl implements ShadeNotificationPresenter{ + @Override + public RemoteInputController.Delegate createRemoteInputDelegate() { + return mNotificationStackScrollLayoutController.createDelegate(); + } - public RemoteInputController.Delegate createRemoteInputDelegate() { - return mNotificationStackScrollLayoutController.createDelegate(); - } - - public boolean hasPulsingNotifications() { - return mNotificationListContainer.hasPulsingNotifications(); - } + @Override + public boolean hasPulsingNotifications() { + return mNotificationListContainer.hasPulsingNotifications(); + } - public ActivatableNotificationView getActivatedChild() { - return mNotificationStackScrollLayoutController.getActivatedChild(); - } + @Override + public ActivatableNotificationView getActivatedChild() { + return mNotificationStackScrollLayoutController.getActivatedChild(); + } - public void setActivatedChild(ActivatableNotificationView o) { - mNotificationStackScrollLayoutController.setActivatedChild(o); + @Override + public void setActivatedChild(ActivatableNotificationView o) { + mNotificationStackScrollLayoutController.setActivatedChild(o); + } } - public void runAfterAnimationFinished(Runnable r) { - mNotificationStackScrollLayoutController.runAfterAnimationFinished(r); + @Override + public ShadeNotificationPresenter getShadeNotificationPresenter() { + return mShadeNotificationPresenter; } - /** - * Initialize objects instead of injecting to avoid circular dependencies. - * - * @param hideExpandedRunnable a runnable to run when we need to hide the expanded panel. - */ + @Override public void initDependencies( CentralSurfaces centralSurfaces, GestureRecorder recorder, Runnable hideExpandedRunnable, - NotificationShelfController notificationShelfController) { + NotificationShelfController notificationShelfController, + HeadsUpManagerPhone headsUpManager) { + setHeadsUpManager(headsUpManager); // TODO(b/254859580): this can be injected. mCentralSurfaces = centralSurfaces; @@ -3371,14 +3408,17 @@ public final class NotificationPanelViewController implements Dumpable { updateMaxDisplayedNotifications(true); } + @Override public void resetTranslation() { mView.setTranslationX(0f); } + @Override public void resetAlpha() { mView.setAlpha(1f); } + @Override public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) { mView.animate().cancel(); return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration( @@ -3386,6 +3426,7 @@ public final class NotificationPanelViewController implements Dumpable { endAction); } + @Override public void resetViewGroupFade() { ViewGroupFadeHelper.reset(mView); } @@ -3398,14 +3439,11 @@ public final class NotificationPanelViewController implements Dumpable { mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener); } - public void setHeaderDebugInfo(String text) { - if (DEBUG_DRAWABLE) mHeaderDebugInfo = text; - } - - public String getHeaderDebugInfo() { - return mHeaderDebugInfo; + String getHeaderDebugInfo() { + return "USER " + mHeadsUpManager.getUser(); } + @Override public void onThemeChanged() { mConfigurationListener.onThemeChanged(); } @@ -3415,22 +3453,17 @@ public final class NotificationPanelViewController implements Dumpable { return mTouchHandler; } + @Override public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() { return mNotificationStackScrollLayoutController; } - public void disable(int state1, int state2, boolean animated) { + @Override + public void disableHeader(int state1, int state2, boolean animated) { mShadeHeaderController.disable(state1, state2, animated); } - /** - * Close the keyguard user switcher if it is open and capable of closing. - * - * Has no effect if user switcher isn't supported, if the user switcher is already closed, or - * if the user switcher uses "simple" mode. The simple user switcher cannot be closed. - * - * @return true if the keyguard user switcher was open, and is now closed - */ + @Override public boolean closeUserSwitcherIfOpen() { if (mKeyguardUserSwitcherController != null) { return mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple( @@ -3455,7 +3488,7 @@ public final class NotificationPanelViewController implements Dumpable { ); } - /** Updates notification panel-specific flags on {@link SysUiState}. */ + @Override public void updateSystemUiStateFlags() { if (SysUiState.DEBUG) { Log.d(TAG, "Updating panel sysui state flags: fullyExpanded=" @@ -3509,7 +3542,7 @@ public final class NotificationPanelViewController implements Dumpable { event.offsetLocation(-deltaX, -deltaY); } - /** If the latency tracker is enabled, begins tracking expand latency. */ + @Override public void startExpandLatencyTracking() { if (mLatencyTracker.isEnabled()) { mLatencyTracker.onActionStart(LatencyTracker.ACTION_EXPAND_PANEL); @@ -3518,7 +3551,7 @@ public final class NotificationPanelViewController implements Dumpable { } private void startOpening(MotionEvent event) { - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); //TODO: keyguard opens QS a different way; log that too? // Log the position of the swipe that opened the panel @@ -3563,7 +3596,7 @@ public final class NotificationPanelViewController implements Dumpable { } /** Called when a MotionEvent is about to trigger Shade expansion. */ - public void startExpandMotion(float newX, float newY, boolean startTracking, + private void startExpandMotion(float newX, float newY, boolean startTracking, float expandedHeight) { if (!mHandlingPointerUp && !mStatusBarStateController.isDozing()) { mQsController.beginJankMonitoring(isFullyCollapsed()); @@ -3578,7 +3611,6 @@ public final class NotificationPanelViewController implements Dumpable { mInitialTouchFromKeyguard = mKeyguardStateController.isShowing(); if (startTracking) { mTouchSlopExceeded = true; - mShadeHeightLogger.logFunctionCall("startExpandMotion"); setExpandedHeight(mInitialOffsetOnTouch); onTrackingStarted(); } @@ -3730,7 +3762,6 @@ public final class NotificationPanelViewController implements Dumpable { @VisibleForTesting void setExpandedHeight(float height) { debugLog("setExpandedHeight(%.1f)", height); - mShadeHeightLogger.logFunctionCall("setExpandedHeight"); setExpandedHeightInternal(height); } @@ -3756,13 +3787,10 @@ public final class NotificationPanelViewController implements Dumpable { return; } - mShadeHeightLogger.logFunctionCall("updateExpandedHeightToMaxHeight"); setExpandedHeight(currentMaxPanelHeight); } private void setExpandedHeightInternal(float h) { - mShadeHeightLogger.logSetExpandedHeightInternal(h, mSystemClock.currentTimeMillis()); - if (isNaN(h)) { Log.wtf(TAG, "ExpandedHeight set to NaN"); } @@ -3795,7 +3823,7 @@ public final class NotificationPanelViewController implements Dumpable { mExpansionDragDownAmountPx = h; mAmbientState.setExpansionFraction(mExpandedFraction); onHeightUpdated(mExpandedHeight); - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); }); } @@ -3819,9 +3847,9 @@ public final class NotificationPanelViewController implements Dumpable { } /** Sets the expanded height relative to a number from 0 to 1. */ - public void setExpandedFraction(float frac) { + @VisibleForTesting + void setExpandedFraction(float frac) { final int maxDist = getMaxPanelTransitionDistance(); - mShadeHeightLogger.logFunctionCall("setExpandedFraction"); setExpandedHeight(maxDist * frac); } @@ -3833,27 +3861,13 @@ public final class NotificationPanelViewController implements Dumpable { return mExpandedFraction; } - /** - * This method should not be used anymore, you should probably use {@link #isShadeFullyOpen()} - * instead. It was overused as indicating if shade is open or we're on keyguard/AOD. - * Moving forward we should be explicit about the what state we're checking. - * @return if panel is covering the screen, which means we're in expanded shade or keyguard/AOD - * - * @deprecated depends on the state you check, use {@link #isShadeFullyOpen()}, - * {@link #isOnAod()}, {@link #isOnKeyguard()} instead. - */ - @Deprecated + @Override public boolean isFullyExpanded() { return mExpandedHeight >= getMaxPanelTransitionDistance(); } - /** - * Returns true if shade is fully opened, that is we're actually in the notification shade - * with QQS or QS. It's different from {@link #isFullyExpanded()} that it will not report - * shade as always expanded if we're on keyguard/AOD. It will return true only when user goes - * from keyguard to shade. - */ - public boolean isShadeFullyOpen() { + @Override + public boolean isShadeFullyExpanded() { if (mBarState == SHADE) { return isFullyExpanded(); } else if (mBarState == SHADE_LOCKED) { @@ -3864,10 +3878,12 @@ public final class NotificationPanelViewController implements Dumpable { } } + @Override public boolean isFullyCollapsed() { return mExpandedFraction <= 0.0f; } + @Override public boolean isCollapsing() { return mClosing || mIsLaunchAnimationRunning; } @@ -3876,22 +3892,21 @@ public final class NotificationPanelViewController implements Dumpable { return mTracking; } - /** Returns whether the shade can be collapsed. */ - public boolean canPanelBeCollapsed() { + @Override + public boolean canBeCollapsed() { return !isFullyCollapsed() && !mTracking && !mClosing; } /** Collapses the shade instantly without animation. */ - public void instantCollapse() { + void instantCollapse() { abortAnimations(); - mShadeHeightLogger.logFunctionCall("instantCollapse"); setExpandedFraction(0f); if (mExpanding) { notifyExpandingFinished(); } if (mInstantExpanding) { mInstantExpanding = false; - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); } } @@ -3900,6 +3915,7 @@ public final class NotificationPanelViewController implements Dumpable { mView.removeCallbacks(mFlingCollapseRunnable); } + @Override public boolean isUnlockHintRunning() { return mHintAnimationRunning; } @@ -3958,7 +3974,7 @@ public final class NotificationPanelViewController implements Dumpable { } /** Returns whether a shade or QS expansion animation is running */ - public boolean isShadeOrQsHeightAnimationRunning() { + private boolean isShadeOrQsHeightAnimationRunning() { return mHeightAnimator != null && !mHintAnimationRunning && !mIsSpringBackAnimation; } @@ -3974,7 +3990,7 @@ public final class NotificationPanelViewController implements Dumpable { public void onAnimationEnd(Animator animation) { setAnimator(null); onAnimationFinished.run(); - updatePanelExpansionAndVisibility(); + updateExpansionAndVisibility(); } }); animator.start(); @@ -4006,7 +4022,6 @@ public final class NotificationPanelViewController implements Dumpable { animator.getAnimatedFraction())); setOverExpansionInternal(expansion, false /* isFromGesture */); } - mShadeHeightLogger.logFunctionCall("height animator update"); setExpandedHeightInternal((float) animation.getAnimatedValue()); }); return animator; @@ -4017,21 +4032,16 @@ public final class NotificationPanelViewController implements Dumpable { mView.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE); } - /** - * Updates the panel expansion and {@link NotificationPanelView} visibility if necessary. - * - * TODO(b/200063118): Could public calls to this method be replaced with calls to - * {@link #updateVisibility()}? That would allow us to make this method private. - */ - public void updatePanelExpansionAndVisibility() { - if (!mMultiShadeEnabled) { - mShadeExpansionStateManager.onPanelExpansionChanged( - mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx); - } + + @Override + public void updateExpansionAndVisibility() { + mShadeExpansionStateManager.onPanelExpansionChanged( + mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx); updateVisibility(); } + @Override public boolean isExpanded() { return mExpandedFraction > 0f || mInstantExpanding @@ -4053,45 +4063,41 @@ public final class NotificationPanelViewController implements Dumpable { return mClosing; } - /** Collapses the shade with an animation duration in milliseconds. */ + @Override public void collapseWithDuration(int animationDuration) { mFixedDuration = animationDuration; collapse(false /* delayed */, 1.0f /* speedUpFactor */); mFixedDuration = NO_FIXED_DURATION; } - /** Returns the NotificationPanelView. */ - public ViewGroup getView() { - // TODO(b/254878364): remove this method, or at least reduce references to it. - return mView; - } - /** */ - public boolean postToView(Runnable action) { + boolean postToView(Runnable action) { return mView.post(action); } /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */ - public boolean handleExternalInterceptTouch(MotionEvent event) { + boolean handleExternalInterceptTouch(MotionEvent event) { return mTouchHandler.onInterceptTouchEvent(event); } - /** Sends an external (e.g. Status Bar) touch event to the Shade touch handler. */ + @Override public boolean handleExternalTouch(MotionEvent event) { return mTouchHandler.onTouchEvent(event); } - /** */ - public void requestLayoutOnView() { + @Override + public void updateTouchableRegion() { + //A layout will ensure that onComputeInternalInsets will be called and after that we can + // resize the layout. Make sure that the window stays small for one frame until the + // touchableRegion is set. mView.requestLayout(); + mNotificationShadeWindowController.setForceWindowCollapsed(true); + postToView(() -> { + mNotificationShadeWindowController.setForceWindowCollapsed(false); + }); } - /** */ - public void resetViewAlphas() { - ViewGroupFadeHelper.reset(mView); - } - - /** */ + @Override public boolean isViewEnabled() { return mView.isEnabled(); } @@ -4119,13 +4125,13 @@ public final class NotificationPanelViewController implements Dumpable { * shade QS are always expanded */ private void closeQsIfPossible() { - boolean openOrOpening = isShadeFullyOpen() || isExpanding(); + boolean openOrOpening = isShadeFullyExpanded() || isExpanding(); if (!(mSplitShadeEnabled && openOrOpening)) { mQsController.closeQs(); } } - /** TODO: remove need for this delegate (b/254870148) */ + @Override public void setQsScrimEnabled(boolean qsScrimEnabled) { mQsController.setScrimEnabled(qsScrimEnabled); } @@ -4228,7 +4234,7 @@ public final class NotificationPanelViewController implements Dumpable { == firstRow))) { requestScrollerTopPaddingUpdate(false /* animate */); } - if (getKeyguardShowing()) { + if (isKeyguardShowing()) { updateMaxDisplayedNotifications(true); } updateExpandedHeightToMaxHeight(); @@ -4474,7 +4480,7 @@ public final class NotificationPanelViewController implements Dumpable { @Override public float getLockscreenShadeDragProgress() { - return NotificationPanelViewController.this.getLockscreenShadeDragProgress(); + return mQsController.getLockscreenShadeDragProgress(); } }; @@ -4484,16 +4490,16 @@ public final class NotificationPanelViewController implements Dumpable { * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the * change. */ + @VisibleForTesting public void showAodUi() { setDozing(true /* dozing */, false /* animate */); mStatusBarStateController.setUpcomingState(KEYGUARD); mStatusBarStateListener.onStateChanged(KEYGUARD); mStatusBarStateListener.onDozeAmountChanged(1f, 1f); - mShadeHeightLogger.logFunctionCall("showAodUi"); setExpandedFraction(1f); } - /** Sets the overstretch amount in raw pixels when dragging down. */ + @Override public void setOverStretchAmount(float amount) { float progress = amount / mView.getHeight(); float overStretch = Interpolators.getOvershootInterpolation(progress); @@ -4585,8 +4591,8 @@ public final class NotificationPanelViewController implements Dumpable { return insets; } - /** Removes any pending runnables that would collapse the panel. */ - public void cancelPendingPanelCollapse() { + @Override + public void cancelPendingCollapse() { mView.removeCallbacks(mMaybeHideExpandedRunnable); } @@ -4659,7 +4665,7 @@ public final class NotificationPanelViewController implements Dumpable { private void onStatusBarWindowStateChanged(@StatusBarManager.WindowVisibleState int state) { if (state != WINDOW_STATE_SHOWING && mStatusBarStateController.getState() == StatusBarState.SHADE) { - collapsePanel( + collapse( false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */); @@ -4671,6 +4677,7 @@ public final class NotificationPanelViewController implements Dumpable { private long mLastTouchDownTime = -1L; /** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */ + @Override public boolean onInterceptTouchEvent(MotionEvent event) { mShadeLog.logMotionEvent(event, "NPVC onInterceptTouchEvent"); if (mQsController.disallowTouches()) { @@ -4932,7 +4939,7 @@ public final class NotificationPanelViewController implements Dumpable { // On expanding, single mouse click expands the panel instead of dragging. if (isFullyCollapsed() && event.isFromSource(InputDevice.SOURCE_MOUSE)) { if (event.getAction() == MotionEvent.ACTION_UP) { - expand(true); + expand(true /* animate */); } return true; } @@ -5062,7 +5069,6 @@ public final class NotificationPanelViewController implements Dumpable { // otherwise {@link NotificationStackScrollLayout} // wrongly enables stack height updates at the start of lockscreen swipe-up mAmbientState.setSwipingUp(h <= 0); - mShadeHeightLogger.logFunctionCall("ACTION_MOVE"); setExpandedHeightInternal(newHeight); } break; @@ -5160,7 +5166,7 @@ public final class NotificationPanelViewController implements Dumpable { @Override public void setTrackedHeadsUp(ExpandableNotificationRow pickedChild) { if (pickedChild != null) { - updateTrackingHeadsUp(pickedChild); + mShadeHeadsUpTracker.updateTrackingHeadsUp(pickedChild); mExpandingFromHeadsUp = true; } // otherwise we update the state when the expansion is finished diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 0318fa570a78..2f4cc1467517 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -283,11 +283,15 @@ public class NotificationShadeWindowViewController { } mLockIconViewController.onTouchEvent( ev, - () -> mService.wakeUpIfDozing( - mClock.uptimeMillis(), - mView, - "LOCK_ICON_TOUCH", - PowerManager.WAKE_REASON_GESTURE) + /* onGestureDetectedRunnable */ + () -> { + mService.userActivity(); + mService.wakeUpIfDozing( + mClock.uptimeMillis(), + mView, + "LOCK_ICON_TOUCH", + PowerManager.WAKE_REASON_GESTURE); + } ); // In case we start outside of the view bounds (below the status bar), we need to diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index 07c8e52e7a6c..b31ec3319781 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -766,7 +766,7 @@ public class QuickSettingsController { /** TODO(b/269742565) Remove this logging */ private void checkCorrectSplitShadeState(float height) { if (mSplitShadeEnabled && height == 0 - && mPanelViewControllerLazy.get().isShadeFullyOpen()) { + && mPanelViewControllerLazy.get().isShadeFullyExpanded()) { Log.wtfStack(TAG, "qsExpansion set to 0 while split shade is expanding or open"); } } @@ -989,13 +989,22 @@ public class QuickSettingsController { // TODO (b/265193930): remove dependency on NPVC float shadeExpandedFraction = mBarState == KEYGUARD - ? mPanelViewControllerLazy.get().getLockscreenShadeDragProgress() + ? getLockscreenShadeDragProgress() : mShadeExpandedFraction; mShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction); mShadeHeaderController.setQsExpandedFraction(qsExpansionFraction); mShadeHeaderController.setQsVisible(mVisible); } + float getLockscreenShadeDragProgress() { + // mTransitioningToFullShadeProgress > 0 means we're doing regular lockscreen to shade + // transition. If that's not the case we should follow QS expansion fraction for when + // user is pulling from the same top to go directly to expanded QS + return getTransitioningToFullShadeProgress() > 0 + ? mLockscreenShadeTransitionController.getQSDragProgress() + : computeExpansionFraction(); + } + /** */ public void updateExpansionEnabledAmbient() { final float scrollRangeToTop = mAmbientState.getTopPadding() - mQuickQsHeaderHeight; @@ -1309,8 +1318,9 @@ public class QuickSettingsController { logNotificationsTopPadding("keyguard", topPadding); return topPadding; } else { - topPadding = mQsFrameTranslateController.getNotificationsTopPadding( - mExpansionHeight, mNotificationStackScrollLayoutController); + topPadding = Math.max(mQsFrameTranslateController.getNotificationsTopPadding( + mExpansionHeight, mNotificationStackScrollLayoutController), + mQuickQsHeaderHeight); logNotificationsTopPadding("default case", topPadding); return topPadding; } @@ -1521,7 +1531,7 @@ public class QuickSettingsController { if (scrollY > 0 && !mFullyExpanded) { // TODO (b/265193930): remove dependency on NPVC // If we are scrolling QS, we should be fully expanded. - mPanelViewControllerLazy.get().expandWithQs(); + mPanelViewControllerLazy.get().expandToQs(); } } @@ -1726,7 +1736,7 @@ public class QuickSettingsController { return true; } // TODO (b/265193930): remove dependency on NPVC - if (mPanelViewControllerLazy.get().getKeyguardShowing() + if (mPanelViewControllerLazy.get().isKeyguardShowing() && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) { // Dragging down on the lockscreen statusbar should prohibit other interactions // immediately, otherwise we'll wait on the touchslop. This is to allow @@ -1790,7 +1800,7 @@ public class QuickSettingsController { return true; } else { mShadeLog.logQsTrackingNotStarted(mInitialTouchY, y, h, touchSlop, - getExpanded(), mPanelViewControllerLazy.get().getKeyguardShowing(), + getExpanded(), mPanelViewControllerLazy.get().isKeyguardShowing(), isExpansionEnabled()); } break; diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java index c1369935db54..826b3ee7a92d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java @@ -35,12 +35,12 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.window.StatusBarWindowController; +import dagger.Lazy; + import java.util.ArrayList; import javax.inject.Inject; -import dagger.Lazy; - /** An implementation of {@link ShadeController}. */ @SysUISingleton public final class ShadeControllerImpl implements ShadeController { @@ -132,13 +132,13 @@ public final class ShadeControllerImpl implements ShadeController { "animateCollapse(): mExpandedVisible=" + mExpandedVisible + "flags=" + flags); } if (getNotificationShadeWindowView() != null - && mNotificationPanelViewController.canPanelBeCollapsed() + && mNotificationPanelViewController.canBeCollapsed() && (flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) { // release focus immediately to kick off focus change transition mNotificationShadeWindowController.setNotificationShadeFocusable(false); mNotificationShadeWindowViewController.cancelExpandHelper(); - mNotificationPanelViewController.collapsePanel(true, delayed, speedUpFactor); + mNotificationPanelViewController.collapse(true, delayed, speedUpFactor); } } @@ -155,7 +155,7 @@ public final class ShadeControllerImpl implements ShadeController { @Override public boolean isShadeFullyOpen() { - return mNotificationPanelViewController.isShadeFullyOpen(); + return mNotificationPanelViewController.isShadeFullyExpanded(); } @Override @@ -268,7 +268,7 @@ public final class ShadeControllerImpl implements ShadeController { } // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) - mNotificationPanelViewController.collapsePanel(false, false, 1.0f); + mNotificationPanelViewController.collapse(false, false, 1.0f); mExpandedVisible = false; notifyVisibilityChanged(false); @@ -290,7 +290,7 @@ public final class ShadeControllerImpl implements ShadeController { notifyExpandedVisibleChanged(false); mCommandQueue.recomputeDisableFlags( mDisplayId, - mNotificationPanelViewController.hideStatusBarIconsWhenExpanded() /* animate */); + mNotificationPanelViewController.shouldHideStatusBarIconsWhenExpanded()); // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in // the bouncer appear animation. diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeightLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeightLogger.kt deleted file mode 100644 index e610b985aef9..000000000000 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeightLogger.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ -package com.android.systemui.shade - -import com.android.systemui.log.dagger.ShadeHeightLog -import com.android.systemui.plugins.log.LogBuffer -import com.android.systemui.plugins.log.LogLevel.DEBUG -import java.text.SimpleDateFormat -import javax.inject.Inject - -private const val TAG = "ShadeHeightLogger" - -/** - * Log the call stack for [NotificationPanelViewController] setExpandedHeightInternal. - * - * Tracking bug: b/261593829 - */ -class ShadeHeightLogger -@Inject constructor( - @ShadeHeightLog private val buffer: LogBuffer, -) { - - private val dateFormat = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS") - - fun logFunctionCall(functionName: String) { - buffer.log(TAG, DEBUG, { - str1 = functionName - }, { - "$str1" - }) - } - - fun logSetExpandedHeightInternal(h: Float, time: Long) { - buffer.log(TAG, DEBUG, { - double1 = h.toDouble() - long1 = time - }, { - "setExpandedHeightInternal=$double1 time=${dateFormat.format(long1)}" - }) - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt new file mode 100644 index 000000000000..b698bd3e6468 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.shade + +import android.view.ViewPropertyAnimator +import com.android.systemui.statusbar.GestureRecorder +import com.android.systemui.statusbar.NotificationShelfController +import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone + +/** + * Allows CentralSurfacesImpl to interact with the shade. Only CentralSurfacesImpl should reference + * this class. If any method in this class is needed outside of CentralSurfacesImpl, it must be + * pulled up into ShadeViewController. + */ +interface ShadeSurface : ShadeViewController { + /** Initialize objects instead of injecting to avoid circular dependencies. */ + fun initDependencies( + centralSurfaces: CentralSurfaces, + recorder: GestureRecorder, + hideExpandedRunnable: Runnable, + notificationShelfController: NotificationShelfController, + headsUpManager: HeadsUpManagerPhone + ) + + /** + * Animate QS collapse by flinging it. If QS is expanded, it will collapse into QQS and stop. If + * in split shade, it will collapse the whole shade. + * + * @param fullyCollapse Do not stop when QS becomes QQS. Fling until QS isn't visible anymore. + */ + fun animateCollapseQs(fullyCollapse: Boolean) + + /** Returns whether the shade can be collapsed. */ + fun canBeCollapsed(): Boolean + + /** Cancels any pending collapses. */ + fun cancelPendingCollapse() + + /** Cancels the views current animation. */ + fun cancelAnimation() + + /** + * Close the keyguard user switcher if it is open and capable of closing. + * + * Has no effect if user switcher isn't supported, if the user switcher is already closed, or if + * the user switcher uses "simple" mode. The simple user switcher cannot be closed. + * + * @return true if the keyguard user switcher was open, and is now closed + */ + fun closeUserSwitcherIfOpen(): Boolean + + /** Input focus transfer is about to happen. */ + fun startWaitingForExpandGesture() + + /** + * Called when this view is no longer waiting for input focus transfer. + * + * There are two scenarios behind this function call. First, input focus transfer has + * successfully happened and this view already received synthetic DOWN event. + * (mExpectingSynthesizedDown == false). Do nothing. + * + * Second, before input focus transfer finished, user may have lifted finger in previous window + * and this window never received synthetic DOWN event. (mExpectingSynthesizedDown == true). In + * this case, we use the velocity to trigger fling event. + * + * @param velocity unit is in px / millis + */ + fun stopWaitingForExpandGesture(cancel: Boolean, velocity: Float) + + /** Animates the view from its current alpha to zero then runs the runnable. */ + fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable): ViewPropertyAnimator + + /** Set whether the bouncer is showing. */ + fun setBouncerShowing(bouncerShowing: Boolean) + + /** + * Sets whether the shade can handle touches and/or animate, canceling any touch handling or + * animations in progress. + */ + fun setTouchAndAnimationDisabled(disabled: Boolean) + + /** + * Sets the dozing state. + * + * @param dozing `true` when dozing. + * @param animate if transition should be animated. + */ + fun setDozing(dozing: Boolean, animate: Boolean) + + /** @see view.setImportantForAccessibility */ + fun setImportantForAccessibility(mode: Int) + + /** Sets Qs ScrimEnabled and updates QS state. */ + fun setQsScrimEnabled(qsScrimEnabled: Boolean) + + /** Sets the view's X translation to zero. */ + fun resetTranslation() + + /** Sets the view's alpha to max. */ + fun resetAlpha() + + /** @see ViewGroupFadeHelper.reset */ + fun resetViewGroupFade() + + /** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */ + fun onBackPressed() + + /** Sets progress of the predictive back animation. */ + fun onBackProgressed(progressFraction: Float) + + /** @see com.android.systemui.keyguard.ScreenLifecycle.Observer.onScreenTurningOn */ + fun onScreenTurningOn() + + /** + * Called when the device's theme changes. + * + * TODO(b/274655539) delete? + */ + fun onThemeChanged() + + /** Updates the shade expansion and [NotificationPanelView] visibility if necessary. */ + fun updateExpansionAndVisibility() + + /** Updates all field values drawn from Resources. */ + fun updateResources() +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt new file mode 100644 index 000000000000..34c9f6d16fff --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.shade + +import android.view.MotionEvent +import android.view.ViewGroup +import com.android.systemui.statusbar.RemoteInputController +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.phone.HeadsUpAppearanceController +import com.android.systemui.statusbar.phone.KeyguardBottomAreaView +import java.util.function.Consumer + +/** + * Controller for the top level shade view + * + * @see NotificationPanelViewController + */ +interface ShadeViewController { + /** Expand the shade either animated or instantly. */ + fun expand(animate: Boolean) + + /** Animates to an expanded shade with QS expanded. If the shade starts expanded, expands QS. */ + fun expandToQs() + + /** + * Expand shade so that notifications are visible. Non-split shade: just expanding shade or + * collapsing QS when they're expanded. Split shade: only expanding shade, notifications are + * always visible + * + * Called when `adb shell cmd statusbar expand-notifications` is executed. + */ + fun expandToNotifications() + + /** Returns whether the shade is expanding or collapsing itself or quick settings. */ + val isExpanding: Boolean + + /** + * Returns whether the shade height is greater than zero (i.e. partially or fully expanded), + * there is a HUN, the shade is animating, or the shade is instantly expanding. + */ + val isExpanded: Boolean + + /** + * Returns whether the shade height is greater than zero or the shade is expecting a synthesized + * down event. + */ + @get:Deprecated("use {@link #isExpanded()} instead") val isPanelExpanded: Boolean + + /** Returns whether the shade is fully expanded in either QS or QQS. */ + val isShadeFullyExpanded: Boolean + + /** + * Animates the collapse of a shade with the given delay and the default duration divided by + * speedUpFactor. + */ + fun collapse(delayed: Boolean, speedUpFactor: Float) + + /** Collapses the shade. */ + fun collapse(animate: Boolean, delayed: Boolean, speedUpFactor: Float) + + /** Collapses the shade with an animation duration in milliseconds. */ + fun collapseWithDuration(animationDuration: Int) + + /** Returns whether the shade is in the process of collapsing. */ + val isCollapsing: Boolean + + /** Returns whether shade's height is zero. */ + val isFullyCollapsed: Boolean + + /** Returns whether the shade is tracking touches for expand/collapse of the shade or QS. */ + val isTracking: Boolean + + /** Returns whether the shade's top level view is enabled. */ + val isViewEnabled: Boolean + + /** Returns whether status bar icons should be hidden when the shade is expanded. */ + fun shouldHideStatusBarIconsWhenExpanded(): Boolean + + /** + * Do not let the user drag the shade up and down for the current touch session. This is + * necessary to avoid shade expansion while/after the bouncer is dismissed. + */ + fun blockExpansionForCurrentTouch() + + /** + * Disables the shade header. + * + * @see ShadeHeaderController.disable + */ + fun disableHeader(state1: Int, state2: Int, animated: Boolean) + + /** If the latency tracker is enabled, begins tracking expand latency. */ + fun startExpandLatencyTracking() + + /** Called before animating Keyguard dismissal, i.e. the animation dismissing the bouncer. */ + fun startBouncerPreHideAnimation() + + /** Called once every minute while dozing. */ + fun dozeTimeTick() + + /** Close guts, notification menus, and QS. Set scroll and overscroll to 0. */ + fun resetViews(animate: Boolean) + + /** Returns the StatusBarState. */ + val barState: Int + + /** + * Returns the bottom part of the keyguard, which contains quick affordances. + * + * TODO(b/275550429): this should be removed. + */ + val keyguardBottomAreaView: KeyguardBottomAreaView? + + /** Returns the NSSL controller. */ + val notificationStackScrollLayoutController: NotificationStackScrollLayoutController + + /** Sets the amount of progress in the status bar launch animation. */ + fun applyLaunchAnimationProgress(linearProgress: Float) + + /** Sets whether the status bar launch animation is currently running. */ + fun setIsLaunchAnimationRunning(running: Boolean) + + /** Sets the alpha value of the shade to a value between 0 and 255. */ + fun setAlpha(alpha: Int, animate: Boolean) + + /** + * Sets the runnable to run after the alpha change animation completes. + * + * @see .setAlpha + */ + fun setAlphaChangeAnimationEndAction(r: Runnable) + + /** Sets whether the screen has temporarily woken up to display notifications. */ + fun setPulsing(pulsing: Boolean) + + /** Sets the top spacing for the ambient indicator. */ + fun setAmbientIndicationTop(ambientIndicationTop: Int, ambientTextVisible: Boolean) + + /** Updates notification panel-specific flags on [SysUiState]. */ + fun updateSystemUiStateFlags() + + /** Ensures that the touchable region is updated. */ + fun updateTouchableRegion() + + // ******* Begin Keyguard Section ********* + /** Animate to expanded shade after a delay in ms. Used for lockscreen to shade transition. */ + fun transitionToExpandedShade(delay: Long) + + /** + * Returns whether the unlock hint animation is running. The unlock hint animation is when the + * user taps the lock screen, causing the contents of the lock screen visually bounce. + */ + val isUnlockHintRunning: Boolean + + /** + * Set the alpha and translationY of the keyguard elements which only show on the lockscreen, + * but not in shade locked / shade. This is used when dragging down to the full shade. + */ + fun setKeyguardTransitionProgress(keyguardAlpha: Float, keyguardTranslationY: Int) + + /** Sets the overstretch amount in raw pixels when dragging down. */ + fun setOverStretchAmount(amount: Float) + + /** + * Sets the alpha value to be set on the keyguard status bar. + * + * @param alpha value between 0 and 1. -1 if the value is to be reset. + */ + fun setKeyguardStatusBarAlpha(alpha: Float) + + /** + * This method should not be used anymore, you should probably use [.isShadeFullyOpen] instead. + * It was overused as indicating if shade is open or we're on keyguard/AOD. Moving forward we + * should be explicit about the what state we're checking. + * + * @return if panel is covering the screen, which means we're in expanded shade or keyguard/AOD + */ + @Deprecated( + "depends on the state you check, use {@link #isShadeFullyExpanded()},\n" + + "{@link #isOnAod()}, {@link #isOnKeyguard()} instead." + ) + fun isFullyExpanded(): Boolean + + /** Sends an external (e.g. Status Bar) touch event to the Shade touch handler. */ + fun handleExternalTouch(event: MotionEvent): Boolean + + // ******* End Keyguard Section ********* + + /** Returns the ShadeHeadsUpTracker. */ + val shadeHeadsUpTracker: ShadeHeadsUpTracker + + /** Returns the ShadeFoldAnimator. */ + val shadeFoldAnimator: ShadeFoldAnimator + + /** Returns the ShadeNotificationPresenter. */ + val shadeNotificationPresenter: ShadeNotificationPresenter +} + +/** Manages listeners for when users begin expanding the shade from a HUN. */ +interface ShadeHeadsUpTracker { + /** Add a listener for when the user starts expanding the shade from a HUN. */ + fun addTrackingHeadsUpListener(listener: Consumer<ExpandableNotificationRow>) + + /** Remove a listener for when the user starts expanding the shade from a HUN. */ + fun removeTrackingHeadsUpListener(listener: Consumer<ExpandableNotificationRow>) + + /** Set the controller for the appearance of HUNs in the icon area and the header itself. */ + fun setHeadsUpAppearanceController(headsUpAppearanceController: HeadsUpAppearanceController?) + + /** The notification row that was touched to initiate shade expansion. */ + val trackedHeadsUpNotification: ExpandableNotificationRow? +} + +/** Handles the lifecycle of the shade's animation that happens when folding a foldable. */ +interface ShadeFoldAnimator { + /** Updates the views to the initial state for the fold to AOD animation. */ + fun prepareFoldToAodAnimation() + + /** + * Starts fold to AOD animation. + * + * @param startAction invoked when the animation starts. + * @param endAction invoked when the animation finishes, also if it was cancelled. + * @param cancelAction invoked when the animation is cancelled, before endAction. + */ + fun startFoldToAodAnimation(startAction: Runnable, endAction: Runnable, cancelAction: Runnable) + + /** Cancels fold to AOD transition and resets view state. */ + fun cancelFoldToAodAnimation() + + /** Returns the main view of the shade. */ + val view: ViewGroup +} + +/** Handles the shade's interactions with StatusBarNotificationPresenter. */ +interface ShadeNotificationPresenter { + /** Returns a new delegate for some view controller pieces of the remote input process. */ + fun createRemoteInputDelegate(): RemoteInputController.Delegate + + /** Returns whether the screen has temporarily woken up to display notifications. */ + fun hasPulsingNotifications(): Boolean + + /** The current activated notification. */ + var activatedChild: ActivatableNotificationView? +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt index fbb51aef06f0..07b686948d7f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar import android.app.ActivityManager import android.content.res.Resources import android.os.SystemProperties +import android.os.Trace import android.util.IndentingPrintWriter import android.util.MathUtils import android.view.CrossWindowBlurListeners @@ -42,7 +43,7 @@ open class BlurUtils @Inject constructor( ) : Dumpable { val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius) val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius) - + private val traceCookie = System.identityHashCode(this) private var lastAppliedBlur = 0 init { @@ -85,10 +86,13 @@ open class BlurUtils @Inject constructor( if (supportsBlursOnWindows()) { it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius) if (lastAppliedBlur == 0 && radius != 0) { + Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, TRACK_NAME, + EARLY_WAKEUP_SLICE_NAME, traceCookie) it.setEarlyWakeupStart() } if (lastAppliedBlur != 0 && radius == 0) { it.setEarlyWakeupEnd() + Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, TRACK_NAME, traceCookie) } lastAppliedBlur = radius } @@ -125,4 +129,9 @@ open class BlurUtils @Inject constructor( it.println("isHighEndGfx: ${ActivityManager.isHighEndGfx()}") } } + + companion object { + const val TRACK_NAME = "BlurUtils" + const val EARLY_WAKEUP_SLICE_NAME = "eEarlyWakeup" + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 9a9503c8cd9c..63e29d105cd8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -320,7 +320,7 @@ class LockscreenShadeTransitionController @Inject constructor( startingChild.onExpandedByGesture( true /* drag down is always an open */) } - notificationPanelController.animateToFullShade(delay) + notificationPanelController.transitionToExpandedShade(delay) callbacks.forEach { it.setTransitionToFullShadeAmount(0f, true /* animated */, delay) } @@ -531,7 +531,7 @@ class LockscreenShadeTransitionController @Inject constructor( } else { // Let's only animate notifications animationHandler = { delay: Long -> - notificationPanelController.animateToFullShade(delay) + notificationPanelController.transitionToExpandedShade(delay) } } goToLockedShadeInternal(expandedView, animationHandler, @@ -649,7 +649,7 @@ class LockscreenShadeTransitionController @Inject constructor( */ private fun performDefaultGoToFullShadeAnimation(delay: Long) { logger.logDefaultGoToFullShadeAnimation(delay) - notificationPanelController.animateToFullShade(delay) + notificationPanelController.transitionToExpandedShade(delay) animateAppear(delay) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index 8874f59d6c17..20af6cadeed5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -16,14 +16,17 @@ package com.android.systemui.statusbar.notification -import android.animation.ObjectAnimator import android.util.FloatProperty +import android.view.animation.Interpolator import androidx.annotation.VisibleForTesting +import androidx.core.animation.ObjectAnimator import com.android.systemui.Dumpable import com.android.systemui.animation.Interpolators +import com.android.systemui.animation.InterpolatorsAndroidX import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.shade.NotificationPanelViewController.WAKEUP_ANIMATION_DELAY_MS import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionListener import com.android.systemui.statusbar.StatusBarState @@ -36,12 +39,17 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController.OnBypassSta import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener +import com.android.systemui.util.doOnEnd +import com.android.systemui.util.doOnStart import java.io.PrintWriter import javax.inject.Inject +import kotlin.math.max import kotlin.math.min @SysUISingleton -class NotificationWakeUpCoordinator @Inject constructor( +class NotificationWakeUpCoordinator +@Inject +constructor( dumpManager: DumpManager, private val mHeadsUpManager: HeadsUpManager, private val statusBarStateController: StatusBarStateController, @@ -49,27 +57,25 @@ class NotificationWakeUpCoordinator @Inject constructor( private val dozeParameters: DozeParameters, private val screenOffAnimationController: ScreenOffAnimationController, private val logger: NotificationWakeUpCoordinatorLogger, -) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, ShadeExpansionListener, +) : + OnHeadsUpChangedListener, + StatusBarStateController.StateListener, + ShadeExpansionListener, Dumpable { - - private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>( - "notificationVisibility") { - - override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) { - coordinator.setVisibilityAmount(value) - } - - override fun get(coordinator: NotificationWakeUpCoordinator): Float? { - return coordinator.mLinearVisibilityAmount - } - } private lateinit var mStackScrollerController: NotificationStackScrollLayoutController private var mVisibilityInterpolator = Interpolators.FAST_OUT_SLOW_IN_REVERSE - private var mLinearDozeAmount: Float = 0.0f - private var mDozeAmount: Float = 0.0f - private var mDozeAmountSource: String = "init" - private var mNotifsHiddenByDozeAmountOverride: Boolean = false + private var inputLinearDozeAmount: Float = 0.0f + private var inputEasedDozeAmount: Float = 0.0f + private var delayedDozeAmountOverride: Float = 0.0f + private var delayedDozeAmountAnimator: ObjectAnimator? = null + /** Valid values: {1f, 0f, null} null => use input */ + private var hardDozeAmountOverride: Float? = null + private var hardDozeAmountOverrideSource: String = "n/a" + private var outputLinearDozeAmount: Float = 0.0f + private var outputEasedDozeAmount: Float = 0.0f + @VisibleForTesting val dozeAmountInterpolator: Interpolator = Interpolators.FAST_OUT_SLOW_IN + private var mNotificationVisibleAmount = 0.0f private var mNotificationsVisible = false private var mNotificationsVisibleForExpansion = false @@ -84,27 +90,32 @@ class NotificationWakeUpCoordinator @Inject constructor( var fullyAwake: Boolean = false var wakingUp = false - set(value) { + private set(value) { field = value willWakeUp = false if (value) { - if (mNotificationsVisible && !mNotificationsVisibleForExpansion && - !bypassController.bypassEnabled) { + if ( + mNotificationsVisible && + !mNotificationsVisibleForExpansion && + !bypassController.bypassEnabled + ) { // We're waking up while pulsing, let's make sure the animation looks nice mStackScrollerController.wakeUpFromPulse() } if (bypassController.bypassEnabled && !mNotificationsVisible) { // Let's make sure our huns become visible once we are waking up in case // they were blocked by the proximity sensor - updateNotificationVisibility(animate = shouldAnimateVisibility(), - increaseSpeed = false) + updateNotificationVisibility( + animate = shouldAnimateVisibility(), + increaseSpeed = false + ) } } } var willWakeUp = false set(value) { - if (!value || mDozeAmount != 0.0f) { + if (!value || outputLinearDozeAmount != 0.0f) { field = value } } @@ -118,8 +129,10 @@ class NotificationWakeUpCoordinator @Inject constructor( // Only when setting pulsing to true we want an immediate update, since we get // this already when the doze service finishes which is usually before we get // the waking up callback - updateNotificationVisibility(animate = shouldAnimateVisibility(), - increaseSpeed = false) + updateNotificationVisibility( + animate = shouldAnimateVisibility(), + increaseSpeed = false + ) } } @@ -133,17 +146,17 @@ class NotificationWakeUpCoordinator @Inject constructor( } } - /** - * True if we can show pulsing heads up notifications - */ + /** True if we can show pulsing heads up notifications */ var canShowPulsingHuns: Boolean = false private set get() { var canShow = pulsing if (bypassController.bypassEnabled) { // We also allow pulsing on the lock screen! - canShow = canShow || (wakingUp || willWakeUp || fullyAwake) && - statusBarStateController.state == StatusBarState.KEYGUARD + canShow = + canShow || + (wakingUp || willWakeUp || fullyAwake) && + statusBarStateController.state == StatusBarState.KEYGUARD // We want to hide the notifications when collapsed too much if (collapsedEnoughToHide) { canShow = false @@ -152,30 +165,38 @@ class NotificationWakeUpCoordinator @Inject constructor( return canShow } - private val bypassStateChangedListener = object : OnBypassStateChangedListener { - override fun onBypassStateChanged(isEnabled: Boolean) { - // When the bypass state changes, we have to check whether we should re-show the - // notifications by clearing the doze amount override which hides them. - maybeClearDozeAmountOverrideHidingNotifs() + private val bypassStateChangedListener = + object : OnBypassStateChangedListener { + override fun onBypassStateChanged(isEnabled: Boolean) { + // When the bypass state changes, we have to check whether we should re-show the + // notifications by clearing the doze amount override which hides them. + maybeClearHardDozeAmountOverrideHidingNotifs() + } } - } init { dumpManager.registerDumpable(this) mHeadsUpManager.addListener(this) statusBarStateController.addCallback(this) bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener) - addListener(object : WakeUpListener { - override fun onFullyHiddenChanged(isFullyHidden: Boolean) { - if (isFullyHidden && mNotificationsVisibleForExpansion) { - // When the notification becomes fully invisible, let's make sure our expansion - // flag also changes. This can happen if the bouncer shows when dragging down - // and then the screen turning off, where we don't reset this state. - setNotificationsVisibleForExpansion(visible = false, animate = false, - increaseSpeed = false) + addListener( + object : WakeUpListener { + override fun onFullyHiddenChanged(isFullyHidden: Boolean) { + if (isFullyHidden && mNotificationsVisibleForExpansion) { + // When the notification becomes fully invisible, let's make sure our + // expansion + // flag also changes. This can happen if the bouncer shows when dragging + // down + // and then the screen turning off, where we don't reset this state. + setNotificationsVisibleForExpansion( + visible = false, + animate = false, + increaseSpeed = false + ) + } } } - }) + ) } fun setStackScroller(stackScrollerController: NotificationStackScrollLayoutController) { @@ -221,15 +242,17 @@ class NotificationWakeUpCoordinator @Inject constructor( wakeUpListeners.remove(listener) } - private fun updateNotificationVisibility( - animate: Boolean, - increaseSpeed: Boolean - ) { + private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) { // TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore var visible = mNotificationsVisibleForExpansion || mHeadsUpManager.hasNotifications() visible = visible && canShowPulsingHuns - if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) { + if ( + !visible && + mNotificationsVisible && + (wakingUp || willWakeUp) && + outputLinearDozeAmount != 0.0f + ) { // let's not make notifications invisible while waking up, otherwise the animation // is strange return @@ -257,7 +280,9 @@ class NotificationWakeUpCoordinator @Inject constructor( override fun onDozeAmountChanged(linear: Float, eased: Float) { logger.logOnDozeAmountChanged(linear = linear, eased = eased) - if (overrideDozeAmountIfAnimatingScreenOff(linear)) { + inputLinearDozeAmount = linear + inputEasedDozeAmount = eased + if (overrideDozeAmountIfAnimatingScreenOff()) { return } @@ -265,35 +290,111 @@ class NotificationWakeUpCoordinator @Inject constructor( return } - if (linear != 1.0f && linear != 0.0f && - (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) { - // Let's notify the scroller that an animation started - notifyAnimationStart(mLinearDozeAmount == 1.0f) + if (clearHardDozeAmountOverride()) { + return } - setDozeAmount(linear, eased, source = "StatusBar") + + updateDozeAmount() } - fun setDozeAmount( - linear: Float, - eased: Float, - source: String, - hidesNotifsByOverride: Boolean = false - ) { - val changed = linear != mLinearDozeAmount - logger.logSetDozeAmount(linear, eased, source, statusBarStateController.state, changed) - mLinearDozeAmount = linear - mDozeAmount = eased - mDozeAmountSource = source - mNotifsHiddenByDozeAmountOverride = hidesNotifsByOverride - mStackScrollerController.setDozeAmount(mDozeAmount) + private fun setHardDozeAmountOverride(dozing: Boolean, source: String) { + logger.logSetDozeAmountOverride(dozing = dozing, source = source) + hardDozeAmountOverride = if (dozing) 1f else 0f + hardDozeAmountOverrideSource = source + updateDozeAmount() + } + + private fun clearHardDozeAmountOverride(): Boolean { + if (hardDozeAmountOverride == null) return false + hardDozeAmountOverride = null + hardDozeAmountOverrideSource = "Cleared: $hardDozeAmountOverrideSource" + updateDozeAmount() + return true + } + + private fun updateDozeAmount() { + // Calculate new doze amount (linear) + val newOutputLinearDozeAmount = + hardDozeAmountOverride ?: max(inputLinearDozeAmount, delayedDozeAmountOverride) + val changed = outputLinearDozeAmount != newOutputLinearDozeAmount + + // notify when the animation is starting + if ( + newOutputLinearDozeAmount != 1.0f && + newOutputLinearDozeAmount != 0.0f && + (outputLinearDozeAmount == 0.0f || outputLinearDozeAmount == 1.0f) + ) { + // Let's notify the scroller that an animation started + notifyAnimationStart(outputLinearDozeAmount == 1.0f) + } + + // Update output doze amount + outputLinearDozeAmount = newOutputLinearDozeAmount + outputEasedDozeAmount = dozeAmountInterpolator.getInterpolation(outputLinearDozeAmount) + logger.logUpdateDozeAmount( + inputLinear = inputLinearDozeAmount, + delayLinear = delayedDozeAmountOverride, + hardOverride = hardDozeAmountOverride, + outputLinear = outputLinearDozeAmount, + state = statusBarStateController.state, + changed = changed + ) + mStackScrollerController.setDozeAmount(outputEasedDozeAmount) updateHideAmount() - if (changed && linear == 0.0f) { + if (changed && outputLinearDozeAmount == 0.0f) { setNotificationsVisible(visible = false, animate = false, increaseSpeed = false) - setNotificationsVisibleForExpansion(visible = false, animate = false, - increaseSpeed = false) + setNotificationsVisibleForExpansion( + visible = false, + animate = false, + increaseSpeed = false + ) + } + } + + /** + * Notifies the wakeup coordinator that we're waking up. + * + * [requestDelayedAnimation] is used to request that we delay the start of the wakeup animation + * in order to wait for a potential fingerprint authentication to arrive, since unlocking during + * the wakeup animation looks chaotic. + * + * If called with [wakingUp] and [requestDelayedAnimation] both `true`, the [WakeUpListener]s + * are guaranteed to receive at least one [WakeUpListener.onDelayedDozeAmountAnimationRunning] + * call with `false` at some point in the near future. A call with `true` before that will + * happen if the animation is not already running. + */ + fun setWakingUp( + wakingUp: Boolean, + requestDelayedAnimation: Boolean, + ) { + logger.logSetWakingUp(wakingUp, requestDelayedAnimation) + this.wakingUp = wakingUp + if (wakingUp && requestDelayedAnimation) { + scheduleDelayedDozeAmountAnimation() } } + private fun scheduleDelayedDozeAmountAnimation() { + val alreadyRunning = delayedDozeAmountAnimator != null + logger.logStartDelayedDozeAmountAnimation(alreadyRunning) + if (alreadyRunning) return + delayedDozeAmount.setValue(this, 1.0f) + delayedDozeAmountAnimator = + ObjectAnimator.ofFloat(this, delayedDozeAmount, 0.0f).apply { + interpolator = InterpolatorsAndroidX.LINEAR + duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong() + startDelay = WAKEUP_ANIMATION_DELAY_MS.toLong() + doOnStart { + wakeUpListeners.forEach { it.onDelayedDozeAmountAnimationRunning(true) } + } + doOnEnd { + delayedDozeAmountAnimator = null + wakeUpListeners.forEach { it.onDelayedDozeAmountAnimationRunning(false) } + } + start() + } + } + override fun onStateChanged(newState: Int) { logger.logOnStateChanged(newState = newState, storedState = state) if (state == StatusBarState.SHADE && newState == StatusBarState.SHADE) { @@ -302,12 +403,15 @@ class NotificationWakeUpCoordinator @Inject constructor( // undefined state, so it's an indication that we should do state cleanup. We override // the doze amount to 0f (not dozing) so that the notifications are no longer hidden. // See: UnlockedScreenOffAnimationController.onFinishedWakingUp() - setDozeAmount(0f, 0f, source = "Override: Shade->Shade (lock cancelled by unlock)") + setHardDozeAmountOverride( + dozing = false, + source = "Override: Shade->Shade (lock cancelled by unlock)" + ) this.state = newState return } - if (overrideDozeAmountIfAnimatingScreenOff(mLinearDozeAmount)) { + if (overrideDozeAmountIfAnimatingScreenOff()) { this.state = newState return } @@ -317,7 +421,7 @@ class NotificationWakeUpCoordinator @Inject constructor( return } - maybeClearDozeAmountOverrideHidingNotifs() + maybeClearHardDozeAmountOverrideHidingNotifs() this.state = newState } @@ -340,15 +444,14 @@ class NotificationWakeUpCoordinator @Inject constructor( /** * @return Whether the doze amount was overridden because bypass is enabled. If true, the - * original doze amount should be ignored. + * original doze amount should be ignored. */ private fun overrideDozeAmountIfBypass(): Boolean { if (bypassController.bypassEnabled) { if (statusBarStateController.state == StatusBarState.KEYGUARD) { - setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)", - hidesNotifsByOverride = true) + setHardDozeAmountOverride(dozing = true, source = "Override: bypass (keyguard)") } else { - setDozeAmount(0f, 0f, source = "Override: bypass (shade)") + setHardDozeAmountOverride(dozing = false, source = "Override: bypass (shade)") } return true } @@ -362,26 +465,28 @@ class NotificationWakeUpCoordinator @Inject constructor( * This fixes bugs where the bypass state changing could result in stale overrides, hiding * notifications either on the inside screen or even after unlock. */ - private fun maybeClearDozeAmountOverrideHidingNotifs() { - if (mNotifsHiddenByDozeAmountOverride) { + private fun maybeClearHardDozeAmountOverrideHidingNotifs() { + if (hardDozeAmountOverride == 1f) { val onKeyguard = statusBarStateController.state == StatusBarState.KEYGUARD val dozing = statusBarStateController.isDozing val bypass = bypassController.bypassEnabled val animating = - screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard() + screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard() // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff] and // [overrideDozeAmountIfBypass] based on 'animating' and 'bypass' respectively, so only // clear the override if both those conditions are cleared. But also require either // !dozing or !onKeyguard because those conditions should indicate that we intend // notifications to be visible, and thus it is safe to unhide them. val willRemove = (!onKeyguard || !dozing) && !bypass && !animating - logger.logMaybeClearDozeAmountOverrideHidingNotifs( - willRemove = willRemove, - onKeyguard = onKeyguard, dozing = dozing, - bypass = bypass, animating = animating, + logger.logMaybeClearHardDozeAmountOverrideHidingNotifs( + willRemove = willRemove, + onKeyguard = onKeyguard, + dozing = dozing, + bypass = bypass, + animating = animating, ) if (willRemove) { - setDozeAmount(0f, 0f, source = "Removed: $mDozeAmountSource") + clearHardDozeAmountOverride() } } } @@ -392,12 +497,11 @@ class NotificationWakeUpCoordinator @Inject constructor( * off and dozeAmount goes from 1f to 0f. * * @return Whether the doze amount was overridden because we are playing the screen off - * animation. If true, the original doze amount should be ignored. + * animation. If true, the original doze amount should be ignored. */ - private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean { + private fun overrideDozeAmountIfAnimatingScreenOff(): Boolean { if (screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()) { - setDozeAmount(1f, 1f, source = "Override: animating screen off", - hidesNotifsByOverride = true) + setHardDozeAmountOverride(dozing = true, source = "Override: animating screen off") return true } @@ -406,41 +510,41 @@ class NotificationWakeUpCoordinator @Inject constructor( private fun startVisibilityAnimation(increaseSpeed: Boolean) { if (mNotificationVisibleAmount == 0f || mNotificationVisibleAmount == 1f) { - mVisibilityInterpolator = if (mNotificationsVisible) - Interpolators.TOUCH_RESPONSE - else - Interpolators.FAST_OUT_SLOW_IN_REVERSE + mVisibilityInterpolator = + if (mNotificationsVisible) Interpolators.TOUCH_RESPONSE + else Interpolators.FAST_OUT_SLOW_IN_REVERSE } val target = if (mNotificationsVisible) 1.0f else 0.0f - val visibilityAnimator = ObjectAnimator.ofFloat(this, mNotificationVisibility, target) - visibilityAnimator.setInterpolator(Interpolators.LINEAR) + val visibilityAnimator = ObjectAnimator.ofFloat(this, notificationVisibility, target) + visibilityAnimator.interpolator = InterpolatorsAndroidX.LINEAR var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong() if (increaseSpeed) { duration = (duration.toFloat() / 1.5F).toLong() } - visibilityAnimator.setDuration(duration) + visibilityAnimator.duration = duration visibilityAnimator.start() mVisibilityAnimator = visibilityAnimator } private fun setVisibilityAmount(visibilityAmount: Float) { + logger.logSetVisibilityAmount(visibilityAmount) mLinearVisibilityAmount = visibilityAmount - mVisibilityAmount = mVisibilityInterpolator.getInterpolation( - visibilityAmount) + mVisibilityAmount = mVisibilityInterpolator.getInterpolation(visibilityAmount) handleAnimationFinished() updateHideAmount() } private fun handleAnimationFinished() { - if (mLinearDozeAmount == 0.0f || mLinearVisibilityAmount == 0.0f) { + if (outputLinearDozeAmount == 0.0f || mLinearVisibilityAmount == 0.0f) { mEntrySetToClearWhenFinished.forEach { it.setHeadsUpAnimatingAway(false) } mEntrySetToClearWhenFinished.clear() } } private fun updateHideAmount() { - val linearAmount = min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount) - val amount = min(1.0f - mVisibilityAmount, mDozeAmount) + val linearAmount = min(1.0f - mLinearVisibilityAmount, outputLinearDozeAmount) + val amount = min(1.0f - mVisibilityAmount, outputEasedDozeAmount) + logger.logSetHideAmount(linearAmount) mStackScrollerController.setHideAmount(linearAmount, amount) notificationsFullyHidden = linearAmount == 1.0f } @@ -458,7 +562,7 @@ class NotificationWakeUpCoordinator @Inject constructor( override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) { var animate = shouldAnimateVisibility() if (!isHeadsUp) { - if (mLinearDozeAmount != 0.0f && mLinearVisibilityAmount != 0.0f) { + if (outputLinearDozeAmount != 0.0f && mLinearVisibilityAmount != 0.0f) { if (entry.isRowDismissed) { // if we animate, we see the shelf briefly visible. Instead we fully animate // the notification and its background out @@ -477,13 +581,16 @@ class NotificationWakeUpCoordinator @Inject constructor( } private fun shouldAnimateVisibility() = - dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking + dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking override fun dump(pw: PrintWriter, args: Array<out String>) { - pw.println("mLinearDozeAmount: $mLinearDozeAmount") - pw.println("mDozeAmount: $mDozeAmount") - pw.println("mDozeAmountSource: $mDozeAmountSource") - pw.println("mNotifsHiddenByDozeAmountOverride: $mNotifsHiddenByDozeAmountOverride") + pw.println("inputLinearDozeAmount: $inputLinearDozeAmount") + pw.println("inputEasedDozeAmount: $inputEasedDozeAmount") + pw.println("delayedDozeAmountOverride: $delayedDozeAmountOverride") + pw.println("hardDozeAmountOverride: $hardDozeAmountOverride") + pw.println("hardDozeAmountOverrideSource: $hardDozeAmountOverrideSource") + pw.println("outputLinearDozeAmount: $outputLinearDozeAmount") + pw.println("outputEasedDozeAmount: $outputEasedDozeAmount") pw.println("mNotificationVisibleAmount: $mNotificationVisibleAmount") pw.println("mNotificationsVisible: $mNotificationsVisible") pw.println("mNotificationsVisibleForExpansion: $mNotificationsVisibleForExpansion") @@ -500,16 +607,53 @@ class NotificationWakeUpCoordinator @Inject constructor( pw.println("canShowPulsingHuns: $canShowPulsingHuns") } + fun logDelayingClockWakeUpAnimation(delayingAnimation: Boolean) { + logger.logDelayingClockWakeUpAnimation(delayingAnimation) + } + interface WakeUpListener { - /** - * Called whenever the notifications are fully hidden or shown - */ + /** Called whenever the notifications are fully hidden or shown */ @JvmDefault fun onFullyHiddenChanged(isFullyHidden: Boolean) {} /** * Called whenever the pulseExpansion changes + * * @param expandingChanged if the user has started or stopped expanding */ @JvmDefault fun onPulseExpansionChanged(expandingChanged: Boolean) {} + + /** + * Called when the animator started by [scheduleDelayedDozeAmountAnimation] begins running + * after the start delay, or after it ends/is cancelled. + */ + @JvmDefault fun onDelayedDozeAmountAnimationRunning(running: Boolean) {} + } + + companion object { + private val notificationVisibility = + object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") { + + override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) { + coordinator.setVisibilityAmount(value) + } + + override fun get(coordinator: NotificationWakeUpCoordinator): Float { + return coordinator.mLinearVisibilityAmount + } + } + + private val delayedDozeAmount = + object : FloatProperty<NotificationWakeUpCoordinator>("delayedDozeAmount") { + + override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) { + coordinator.delayedDozeAmountOverride = value + coordinator.logger.logSetDelayDozeAmountOverride(value) + coordinator.updateDozeAmount() + } + + override fun get(coordinator: NotificationWakeUpCoordinator): Float { + return coordinator.delayedDozeAmountOverride + } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt index 88d9ffcdcf3e..dd3c2a9df3e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt @@ -22,50 +22,75 @@ import javax.inject.Inject class NotificationWakeUpCoordinatorLogger @Inject constructor(@NotificationLockscreenLog private val buffer: LogBuffer) { - private var lastSetDozeAmountLogWasFractional = false + private var allowThrottle = true + private var lastSetDozeAmountLogInputWasFractional = false + private var lastSetDozeAmountLogDelayWasFractional = false private var lastSetDozeAmountLogState = -1 - private var lastSetDozeAmountLogSource = "undefined" + private var lastSetHardOverride: Float? = null private var lastOnDozeAmountChangedLogWasFractional = false + private var lastSetDelayDozeAmountOverrideLogWasFractional = false + private var lastSetVisibilityAmountLogWasFractional = false + private var lastSetHideAmountLogWasFractional = false + private var lastSetHideAmount = -1f - fun logSetDozeAmount( - linear: Float, - eased: Float, - source: String, + fun logUpdateDozeAmount( + inputLinear: Float, + delayLinear: Float, + hardOverride: Float?, + outputLinear: Float, state: Int, changed: Boolean, ) { // Avoid logging on every frame of the animation if important values are not changing - val isFractional = linear != 1f && linear != 0f + val isInputFractional = inputLinear != 1f && inputLinear != 0f + val isDelayFractional = delayLinear != 1f && delayLinear != 0f if ( - lastSetDozeAmountLogWasFractional && - isFractional && + (isInputFractional || isDelayFractional) && + lastSetDozeAmountLogInputWasFractional == isInputFractional && + lastSetDozeAmountLogDelayWasFractional == isDelayFractional && lastSetDozeAmountLogState == state && - lastSetDozeAmountLogSource == source + lastSetHardOverride == hardOverride && + allowThrottle ) { return } - lastSetDozeAmountLogWasFractional = isFractional + lastSetDozeAmountLogInputWasFractional = isInputFractional + lastSetDozeAmountLogDelayWasFractional = isDelayFractional lastSetDozeAmountLogState = state - lastSetDozeAmountLogSource = source + lastSetHardOverride = hardOverride buffer.log( TAG, DEBUG, { - double1 = linear.toDouble() - str2 = eased.toString() - str3 = source + double1 = inputLinear.toDouble() + str1 = hardOverride.toString() + str2 = outputLinear.toString() + str3 = delayLinear.toString() int1 = state bool1 = changed }, { - "setDozeAmount(linear=$double1, eased=$str2, source=$str3)" + + "updateDozeAmount() inputLinear=$double1 delayLinear=$str3" + + " hardOverride=$str1 outputLinear=$str2" + " state=${StatusBarState.toString(int1)} changed=$bool1" } ) } - fun logMaybeClearDozeAmountOverrideHidingNotifs( + fun logSetDozeAmountOverride(dozing: Boolean, source: String) { + buffer.log( + TAG, + DEBUG, + { + bool1 = dozing + str1 = source + }, + { "setDozeAmountOverride(dozing=$bool1, source=\"$str1\")" } + ) + } + + fun logMaybeClearHardDozeAmountOverrideHidingNotifs( willRemove: Boolean, onKeyguard: Boolean, dozing: Boolean, @@ -80,14 +105,14 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) { "willRemove=$willRemove onKeyguard=$onKeyguard dozing=$dozing" + " bypass=$bypass animating=$animating" }, - { "maybeClearDozeAmountOverrideHidingNotifs() $str1" } + { "maybeClearHardDozeAmountOverrideHidingNotifs() $str1" } ) } fun logOnDozeAmountChanged(linear: Float, eased: Float) { // Avoid logging on every frame of the animation when values are fractional val isFractional = linear != 1f && linear != 0f - if (lastOnDozeAmountChangedLogWasFractional && isFractional) return + if (lastOnDozeAmountChangedLogWasFractional && isFractional && allowThrottle) return lastOnDozeAmountChangedLogWasFractional = isFractional buffer.log( TAG, @@ -100,6 +125,47 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) { ) } + fun logSetDelayDozeAmountOverride(linear: Float) { + // Avoid logging on every frame of the animation when values are fractional + val isFractional = linear != 1f && linear != 0f + if (lastSetDelayDozeAmountOverrideLogWasFractional && isFractional && allowThrottle) return + lastSetDelayDozeAmountOverrideLogWasFractional = isFractional + buffer.log( + TAG, + DEBUG, + { double1 = linear.toDouble() }, + { "setDelayDozeAmountOverride($double1)" } + ) + } + + fun logSetVisibilityAmount(linear: Float) { + // Avoid logging on every frame of the animation when values are fractional + val isFractional = linear != 1f && linear != 0f + if (lastSetVisibilityAmountLogWasFractional && isFractional && allowThrottle) return + lastSetVisibilityAmountLogWasFractional = isFractional + buffer.log(TAG, DEBUG, { double1 = linear.toDouble() }, { "setVisibilityAmount($double1)" }) + } + + fun logSetHideAmount(linear: Float) { + // Avoid logging the same value repeatedly + if (lastSetHideAmount == linear && allowThrottle) return + lastSetHideAmount = linear + // Avoid logging on every frame of the animation when values are fractional + val isFractional = linear != 1f && linear != 0f + if (lastSetHideAmountLogWasFractional && isFractional && allowThrottle) return + lastSetHideAmountLogWasFractional = isFractional + buffer.log(TAG, DEBUG, { double1 = linear.toDouble() }, { "setHideAmount($double1)" }) + } + + fun logStartDelayedDozeAmountAnimation(alreadyRunning: Boolean) { + buffer.log( + TAG, + DEBUG, + { bool1 = alreadyRunning }, + { "startDelayedDozeAmountAnimation() alreadyRunning=$bool1" } + ) + } + fun logOnStateChanged(newState: Int, storedState: Int) { buffer.log( TAG, @@ -114,6 +180,27 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) { } ) } + + fun logSetWakingUp(wakingUp: Boolean, requestDelayedAnimation: Boolean) { + buffer.log( + TAG, + DEBUG, + { + bool1 = wakingUp + bool2 = requestDelayedAnimation + }, + { "setWakingUp(wakingUp=$bool1, requestDelayedAnimation=$bool2)" } + ) + } + + fun logDelayingClockWakeUpAnimation(delayingAnimation: Boolean) { + buffer.log( + TAG, + DEBUG, + { bool1 = delayingAnimation }, + { "logDelayingClockWakeUpAnimation($bool1)" } + ) + } } private const val TAG = "NotificationWakeUpCoordinator" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index c9f31bad74c0..8aeefeeac211 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -307,7 +307,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { } entriesToLocallyDismiss.add(entry); - if (!isCanceled(entry)) { + if (!entry.isCanceled()) { // send message to system server if this notification hasn't already been cancelled mBgExecutor.execute(() -> { try { @@ -387,7 +387,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { entry.setDismissState(DISMISSED); mLogger.logNotifDismissed(entry); - if (isCanceled(entry)) { + if (entry.isCanceled()) { canceledEntries.add(entry); } else { // Mark any children as dismissed as system server will auto-dismiss them as well @@ -396,7 +396,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { if (shouldAutoDismissChildren(otherEntry, entry.getSbn().getGroupKey())) { otherEntry.setDismissState(PARENT_DISMISSED); mLogger.logChildDismissed(otherEntry); - if (isCanceled(otherEntry)) { + if (otherEntry.isCanceled()) { canceledEntries.add(otherEntry); } } @@ -523,7 +523,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { + logKey(entry))); } - if (!isCanceled(entry)) { + if (!entry.isCanceled()) { throw mEulogizer.record( new IllegalStateException("Cannot remove notification " + logKey(entry) + ": has not been marked for removal")); @@ -587,7 +587,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { private void applyRanking(@NonNull RankingMap rankingMap) { ArrayMap<String, NotificationEntry> currentEntriesWithoutRankings = null; for (NotificationEntry entry : mNotificationSet.values()) { - if (!isCanceled(entry)) { + if (!entry.isCanceled()) { // TODO: (b/148791039) We should crash if we are ever handed a ranking with // incomplete entries. Right now, there's a race condition in NotificationListener @@ -815,15 +815,6 @@ public class NotifCollection implements Dumpable, PipelineDumpable { return ranking; } - /** - * True if the notification has been canceled by system server. Usually, such notifications are - * immediately removed from the collection, but can sometimes stick around due to lifetime - * extenders. - */ - private boolean isCanceled(NotificationEntry entry) { - return entry.mCancellationReason != REASON_NOT_CANCELED; - } - private boolean cannotBeLifetimeExtended(NotificationEntry entry) { final boolean locallyDismissedByUser = entry.getDismissState() != NOT_DISMISSED; final boolean systemServerReportedUserCancel = 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 3399f9df7fd5..f7790e861e27 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 @@ -321,6 +321,15 @@ public final class NotificationEntry extends ListEntry { mDismissState = requireNonNull(dismissState); } + /** + * True if the notification has been canceled by system server. Usually, such notifications are + * immediately removed from the collection, but can sometimes stick around due to lifetime + * extenders. + */ + public boolean isCanceled() { + return mCancellationReason != REASON_NOT_CANCELED; + } + @Nullable public NotifFilter getExcludingFilter() { return getAttachState().getExcludingFilter(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index 6c84fefe2d38..ea5cb308a2d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -190,7 +190,9 @@ public class RankingCoordinator implements Coordinator { "DndSuppressingVisualEffects") { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { - if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) { + if ((mStatusBarStateController.isDozing() + || mStatusBarStateController.getDozeAmount() == 1f) + && entry.shouldSuppressAmbient()) { return true; } @@ -200,6 +202,20 @@ public class RankingCoordinator implements Coordinator { private final StatusBarStateController.StateListener mStatusBarStateCallback = new StatusBarStateController.StateListener() { + private boolean mPrevDozeAmountIsOne = false; + + @Override + public void onDozeAmountChanged(float linear, float eased) { + StatusBarStateController.StateListener.super.onDozeAmountChanged(linear, eased); + + boolean dozeAmountIsOne = linear == 1f; + if (mPrevDozeAmountIsOne != dozeAmountIsOne) { + mDndVisualEffectsFilter.invalidateList("dozeAmount changed to " + + (dozeAmountIsOne ? "one" : "not one")); + mPrevDozeAmountIsOne = dozeAmountIsOne; + } + } + @Override public void onDozingChanged(boolean isDozing) { mDndVisualEffectsFilter.invalidateList("onDozingChanged to " + isDozing); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt index 0d9a654fa485..058545689c01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt @@ -46,7 +46,7 @@ class NotifUiAdjustmentProvider @Inject constructor( private val userTracker: UserTracker ) { private val dirtyListeners = ListenerSet<Runnable>() - private var isSnoozeEnabled = false + private var isSnoozeSettingsEnabled = false /** * Update the snooze enabled value on user switch @@ -95,7 +95,7 @@ class NotifUiAdjustmentProvider @Inject constructor( } private fun updateSnoozeEnabled() { - isSnoozeEnabled = + isSnoozeSettingsEnabled = secureSettings.getIntForUser(SHOW_NOTIFICATION_SNOOZE, 0, UserHandle.USER_CURRENT) == 1 } @@ -118,7 +118,7 @@ class NotifUiAdjustmentProvider @Inject constructor( smartActions = entry.ranking.smartActions, smartReplies = entry.ranking.smartReplies, isConversation = entry.ranking.isConversation, - isSnoozeEnabled = isSnoozeEnabled, + isSnoozeEnabled = isSnoozeSettingsEnabled && !entry.isCanceled, isMinimized = isEntryMinimized(entry), needsRedaction = lockscreenUserManager.needsRedaction(entry), ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt index 27fe747e6be8..a352f23bfc1c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt @@ -234,6 +234,14 @@ class NotificationInterruptLogger @Inject constructor( }) } + fun logNoPulsingNotificationHidden(entry: NotificationEntry) { + buffer.log(TAG, DEBUG, { + str1 = entry.logKey + }, { + "No pulsing: notification hidden on lock screen: $str1" + }) + } + fun logNoPulsingNotImportant(entry: NotificationEntry) { buffer.log(TAG, DEBUG, { str1 = entry.logKey diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java index bfb6416ac78a..9a1747a9c931 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java @@ -61,6 +61,12 @@ public interface NotificationInterruptStateProvider { */ NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(false), /** + * Notification should not FSI due to having suppressive BubbleMetadata. This blocks a + * potentially malicious use of flags that previously allowed apps to escalate a HUN to an + * FSI even while the device was unlocked. + */ + NO_FSI_SUPPRESSIVE_BUBBLE_METADATA(false), + /** * Device screen is off, so the FSI should launch. */ FSI_DEVICE_NOT_INTERACTIVE(true), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java index 4aaa7ca61d34..ca762fc1ddc2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.interruption; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD; +import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI; @@ -82,6 +83,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter @UiEvent(doc = "FSI suppressed for suppressive GroupAlertBehavior") FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(1235), + @UiEvent(doc = "FSI suppressed for suppressive BubbleMetadata") + FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA(1353), + @UiEvent(doc = "FSI suppressed for requiring neither HUN nor keyguard") FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236), @@ -273,6 +277,16 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter suppressedByDND); } + // If the notification has suppressive BubbleMetadata, block FSI and warn. + Notification.BubbleMetadata bubbleMetadata = sbn.getNotification().getBubbleMetadata(); + if (bubbleMetadata != null && bubbleMetadata.isNotificationSuppressed()) { + // b/274759612: Detect and report an event when a notification has both an FSI and a + // suppressive BubbleMetadata, and now correctly block the FSI from firing. + return getDecisionGivenSuppression( + FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA, + suppressedByDND); + } + // Notification is coming from a suspended package, block FSI if (entry.getRanking().isSuspended()) { return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_SUSPENDED, @@ -351,6 +365,14 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter mLogger.logNoFullscreenWarning(entry, decision + ": GroupAlertBehavior will prevent HUN"); return; + case NO_FSI_SUPPRESSIVE_BUBBLE_METADATA: + android.util.EventLog.writeEvent(0x534e4554, "274759612", uid, + "bubbleMetadata"); + mUiEventLogger.log(FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA, uid, + packageName); + mLogger.logNoFullscreenWarning(entry, + decision + ": BubbleMetadata may prevent HUN"); + return; case NO_FSI_NO_HUN_OR_KEYGUARD: android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "no hun or keyguard"); @@ -482,6 +504,12 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter return false; } + if (entry.getRanking().getLockscreenVisibilityOverride() + == Notification.VISIBILITY_PRIVATE) { + if (log) mLogger.logNoPulsingNotificationHidden(entry); + return false; + } + if (entry.getImportance() < NotificationManager.IMPORTANCE_DEFAULT) { if (log) mLogger.logNoPulsingNotImportant(entry); return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java index 797038d1d615..ce6dd893cb69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java @@ -110,7 +110,7 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout public void bind(@Nullable CharSequence title, @Nullable CharSequence text, @Nullable View contentView) { - mTitleView.setText(title.toString()); + mTitleView.setText(title != null ? title.toString() : title); mTitleView.setVisibility(TextUtils.isEmpty(title) ? GONE : VISIBLE); if (TextUtils.isEmpty(text)) { mTextView.setVisibility(GONE); 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 46f1bb5ebd6f..e6e6b9950d40 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 @@ -65,6 +65,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.wmshell.BubblesManager; @@ -119,6 +120,7 @@ public class NotificationGutsManager implements NotifGutsViewManager { private final UiEventLogger mUiEventLogger; private final ShadeController mShadeController; private NotifGutsViewListener mGutsListener; + private final HeadsUpManagerPhone mHeadsUpManagerPhone; @Inject public NotificationGutsManager(Context context, @@ -141,7 +143,8 @@ public class NotificationGutsManager implements NotifGutsViewManager { NotificationLockscreenUserManager notificationLockscreenUserManager, StatusBarStateController statusBarStateController, DeviceProvisionedController deviceProvisionedController, - MetricsLogger metricsLogger) { + MetricsLogger metricsLogger, + HeadsUpManagerPhone headsUpManagerPhone) { mContext = context; mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mMainHandler = mainHandler; @@ -163,6 +166,7 @@ public class NotificationGutsManager implements NotifGutsViewManager { mStatusBarStateController = statusBarStateController; mDeviceProvisionedController = deviceProvisionedController; mMetricsLogger = metricsLogger; + mHeadsUpManagerPhone = headsUpManagerPhone; } public void setUpWithPresenter(NotificationPresenter presenter, @@ -259,7 +263,7 @@ public class NotificationGutsManager implements NotifGutsViewManager { if (mGutsListener != null) { mGutsListener.onGutsClose(entry); } - String key = entry.getKey(); + mHeadsUpManagerPhone.setGutsShown(row.getEntry(), false); }); View gutsView = item.getGutsView(); @@ -420,7 +424,7 @@ public class NotificationGutsManager implements NotifGutsViewManager { } /** - * Sets up the {@link ConversationInfo} inside the notification row's guts. + * Sets up the {@link NotificationConversationInfo} inside the notification row's guts. * @param row view to set up the guts for * @param notificationInfoView view to set up/bind within {@code row} */ @@ -641,6 +645,7 @@ public class NotificationGutsManager implements NotifGutsViewManager { row.closeRemoteInput(); mListContainer.onHeightChanged(row, true /* needsAnimation */); mGutsMenuItem = menuItem; + mHeadsUpManagerPhone.setGutsShown(row.getEntry(), true); } }; guts.post(mOpenRunnable); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java index adbfa755b63c..5f4c9267ee4a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java @@ -290,6 +290,9 @@ public class NotificationSnooze extends LinearLayout int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification : com.android.internal.R.drawable.ic_expand_notification; mExpandButton.setImageResource(drawableId); + mExpandButton.setContentDescription(mContext.getString(show + ? com.android.internal.R.string.expand_button_content_description_expanded + : com.android.internal.R.string.expand_button_content_description_collapsed)); if (mExpanded != show) { mExpanded = show; animateSnoozeOptions(show); @@ -373,6 +376,7 @@ public class NotificationSnooze extends LinearLayout } else if (id == R.id.notification_snooze) { // Toggle snooze options showSnoozeOptions(!mExpanded); + mSnoozeView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); mMetricsLogger.write(!mExpanded ? OPTIONS_OPEN_LOG : OPTIONS_CLOSE_LOG); } else { // Undo snooze was selected @@ -401,6 +405,7 @@ public class NotificationSnooze extends LinearLayout public View getContentView() { // Reset the view before use setSelected(mDefaultOption, false); + showSnoozeOptions(false); return this; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index a2de3c38d090..e47e4146d4c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -5638,6 +5638,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public void setDozeAmount(float dozeAmount) { mAmbientState.setDozeAmount(dozeAmount); updateContinuousBackgroundDrawing(); + updateStackPosition(); requestChildrenUpdate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 769edf74f838..792746c60134 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -56,7 +56,6 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.ExpandHelper; import com.android.systemui.Gefingerpoken; -import com.android.systemui.SwipeHelper; import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.Main; @@ -371,11 +370,6 @@ public class NotificationStackScrollLayoutController { if (translatingParentView != null && row == translatingParentView) { mSwipeHelper.clearExposedMenuView(); mSwipeHelper.clearTranslatingParentView(); - if (row instanceof ExpandableNotificationRow) { - mHeadsUpManager.setMenuShown( - ((ExpandableNotificationRow) row).getEntry(), false); - - } } } @@ -386,7 +380,6 @@ public class NotificationStackScrollLayoutController { mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_REVEAL_GEAR) .setType(MetricsEvent.TYPE_ACTION)); - mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true); mSwipeHelper.onMenuShown(row); mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, @@ -748,7 +741,6 @@ public class NotificationStackScrollLayoutController { !mKeyguardBypassController.getBypassEnabled()); mSwipeHelper = mNotificationSwipeHelperBuilder - .setSwipeDirection(SwipeHelper.X) .setNotificationCallback(mNotificationCallback) .setOnMenuEventListener(mMenuEventListener) .build(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index b476b683463f..91f53b630c73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -76,11 +76,10 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc ViewConfiguration viewConfiguration, FalsingManager falsingManager, FeatureFlags featureFlags, - int swipeDirection, NotificationCallback callback, NotificationMenuRowPlugin.OnMenuEventListener menuListener, NotificationRoundnessManager notificationRoundnessManager) { - super(swipeDirection, callback, resources, viewConfiguration, falsingManager, featureFlags); + super(callback, resources, viewConfiguration, falsingManager, featureFlags); mNotificationRoundnessManager = notificationRoundnessManager; mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES); mMenuListener = menuListener; @@ -416,22 +415,12 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc } @Override - public boolean swipedFastEnough(float translation, float viewSize) { - return swipedFastEnough(); - } - - @Override @VisibleForTesting protected boolean swipedFastEnough() { return super.swipedFastEnough(); } @Override - public boolean swipedFarEnough(float translation, float viewSize) { - return swipedFarEnough(); - } - - @Override @VisibleForTesting protected boolean swipedFarEnough() { return super.swipedFarEnough(); @@ -554,7 +543,6 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc private final ViewConfiguration mViewConfiguration; private final FalsingManager mFalsingManager; private final FeatureFlags mFeatureFlags; - private int mSwipeDirection; private NotificationCallback mNotificationCallback; private NotificationMenuRowPlugin.OnMenuEventListener mOnMenuEventListener; private NotificationRoundnessManager mNotificationRoundnessManager; @@ -570,11 +558,6 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc mNotificationRoundnessManager = notificationRoundnessManager; } - Builder setSwipeDirection(int swipeDirection) { - mSwipeDirection = swipeDirection; - return this; - } - Builder setNotificationCallback(NotificationCallback notificationCallback) { mNotificationCallback = notificationCallback; return this; @@ -588,7 +571,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc NotificationSwipeHelper build() { return new NotificationSwipeHelper(mResources, mViewConfiguration, mFalsingManager, - mFeatureFlags, mSwipeDirection, mNotificationCallback, mOnMenuEventListener, + mFeatureFlags, mNotificationCallback, mOnMenuEventListener, mNotificationRoundnessManager); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 7f8c1351aa7a..9272f06076fa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -53,6 +53,7 @@ import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.statusbar.LightRevealScrim; import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.util.Compile; import java.io.PrintWriter; @@ -71,6 +72,7 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn boolean DEBUG_MEDIA_FAKE_ARTWORK = false; boolean DEBUG_CAMERA_LIFT = false; boolean DEBUG_WINDOW_STATE = false; + boolean DEBUG_WAKEUP_DELAY = Compile.IS_DEBUG; // additional instrumentation for testing purposes; intended to be left on during development boolean CHATTY = DEBUG; boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; @@ -536,6 +538,8 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void extendDozePulse(); + boolean shouldDelayWakeUpAnimation(); + public static class KeyboardShortcutsMessage { final int mDeviceId; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index b8c7a1d77810..e7760159bff5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -67,12 +67,12 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; +import dagger.Lazy; + import java.util.Optional; import javax.inject.Inject; -import dagger.Lazy; - /** */ @CentralSurfacesComponent.CentralSurfacesScope public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callbacks { @@ -218,7 +218,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba return; } - mNotificationPanelViewController.expandShadeToNotifications(); + mNotificationPanelViewController.expandToNotifications(); } @Override @@ -234,7 +234,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba // Settings are not available in setup if (!mDeviceProvisionedController.isCurrentUserSetup()) return; - mNotificationPanelViewController.expandWithQs(); + mNotificationPanelViewController.expandToQs(); } @Override @@ -300,7 +300,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba } } - mNotificationPanelViewController.disable(state1, state2, animate); + mNotificationPanelViewController.disableHeader(state1, state2, animate); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 2bc09a100976..aabe0cb9794c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -67,6 +67,7 @@ import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.graphics.Point; import android.hardware.devicestate.DeviceStateManager; +import android.hardware.fingerprint.FingerprintManager; import android.metrics.LogMaker; import android.net.Uri; import android.os.Binder; @@ -262,6 +263,7 @@ import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; /** * A class handling initialization and coordination between some of the key central surfaces in @@ -453,10 +455,20 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting DozeServiceHost mDozeServiceHost; - private boolean mWakeUpComingFromTouch; private LightRevealScrim mLightRevealScrim; private PowerButtonReveal mPowerButtonReveal; + private boolean mWakeUpComingFromTouch; + + /** + * Whether we should delay the wakeup animation (which shows the notifications and moves the + * clock view). This is typically done when waking up from a 'press to unlock' gesture on a + * device with a side fingerprint sensor, so that if the fingerprint scan is successful, we + * can play the unlock animation directly rather than interrupting the wakeup animation part + * way through. + */ + private boolean mShouldDelayWakeUpAnimation = false; + private final Object mQueueLock = new Object(); private final PulseExpansionHandler mPulseExpansionHandler; @@ -518,6 +530,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final MessageRouter mMessageRouter; private final WallpaperManager mWallpaperManager; private final UserTracker mUserTracker; + private final Provider<FingerprintManager> mFingerprintManager; private CentralSurfacesComponent mCentralSurfacesComponent; @@ -683,7 +696,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void onBackProgressed(BackEvent event) { if (shouldBackBeHandled()) { - if (mNotificationPanelViewController.canPanelBeCollapsed()) { + if (mNotificationPanelViewController.canBeCollapsed()) { float fraction = event.getProgress(); mNotificationPanelViewController.onBackProgressed(fraction); } @@ -790,7 +803,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { Lazy<CameraLauncher> cameraLauncherLazy, Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy, AlternateBouncerInteractor alternateBouncerInteractor, - UserTracker userTracker + UserTracker userTracker, + Provider<FingerprintManager> fingerprintManager ) { mContext = context; mNotificationsController = notificationsController; @@ -873,6 +887,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mCameraLauncherLazy = cameraLauncherLazy; mAlternateBouncerInteractor = alternateBouncerInteractor; mUserTracker = userTracker; + mFingerprintManager = fingerprintManager; mLockscreenShadeTransitionController = lockscreenShadeTransitionController; mStartingSurfaceOptional = startingSurfaceOptional; @@ -1255,14 +1270,13 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // re-display the notification panel if necessary (for example, if // a heads-up notification was being displayed and should continue being // displayed). - mNotificationPanelViewController.updatePanelExpansionAndVisibility(); + mNotificationPanelViewController.updateExpansionAndVisibility(); setBouncerShowingForStatusBarComponents(mBouncerShowing); checkBarModes(); }); initializer.initializeStatusBar(mCentralSurfacesComponent); mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView); - mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); createNavigationBar(result); @@ -1335,7 +1349,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { this, mGestureRec, mShadeController::makeExpandedInvisible, - mNotificationShelfController); + mNotificationShelfController, + mHeadsUpManager); BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop); mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front), @@ -2073,16 +2088,16 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } if (start) { - mNotificationPanelViewController.startWaitingForOpenPanelGesture(); + mNotificationPanelViewController.startWaitingForExpandGesture(); } else { - mNotificationPanelViewController.stopWaitingForOpenPanelGesture(cancel, velocity); + mNotificationPanelViewController.stopWaitingForExpandGesture(cancel, velocity); } } @Override public void animateCollapseQuickSettings() { if (mState == StatusBarState.SHADE) { - mNotificationPanelViewController.collapsePanel( + mNotificationPanelViewController.collapse( true, false /* delayed */, 1.0f /* speedUpFactor */); } } @@ -3181,6 +3196,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } + public boolean shouldDelayWakeUpAnimation() { + return mShouldDelayWakeUpAnimation; + } + private void updateDozingState() { Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); Trace.beginSection("CentralSurfaces#updateDozingState"); @@ -3191,11 +3210,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { boolean keyguardVisibleOrWillBe = keyguardVisible || (mDozing && mDozeParameters.shouldDelayKeyguardShow()); - boolean wakeAndUnlock = mBiometricUnlockController.getMode() - == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; - boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock) - || (mDozing && mDozeParameters.shouldControlScreenOff() - && keyguardVisibleOrWillBe); + boolean animate = (!mDozing && shouldAnimateDozeWakeup()) + || (mDozing && mDozeParameters.shouldControlScreenOff() && keyguardVisibleOrWillBe); mNotificationPanelViewController.setDozing(mDozing, animate); updateQsExpansionEnabled(); @@ -3277,14 +3293,14 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return true; } if (mQsController.getExpanded()) { - mNotificationPanelViewController.animateCloseQs(false); + mNotificationPanelViewController.animateCollapseQs(false); return true; } if (mNotificationPanelViewController.closeUserSwitcherIfOpen()) { return true; } if (shouldBackBeHandled()) { - if (mNotificationPanelViewController.canPanelBeCollapsed()) { + if (mNotificationPanelViewController.canBeCollapsed()) { // this is the Shade dismiss animation, so make sure QQS closes when it ends. mNotificationPanelViewController.onBackPressed(); mShadeController.animateCollapseShade(); @@ -3550,7 +3566,44 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { DejankUtils.startDetectingBlockingIpcs(tag); mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { mDeviceInteractive = true; - mWakeUpCoordinator.setWakingUp(true); + + if (shouldAnimateDozeWakeup()) { + // If this is false, the power button must be physically pressed in order to + // trigger fingerprint authentication. + final boolean touchToUnlockAnytime = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED, + -1, + mUserTracker.getUserId()) > 0; + + // Delay if we're waking up, not mid-doze animation (which means we are + // cancelling a sleep), from the power button, on a device with a power button + // FPS, and 'press to unlock' is required. + mShouldDelayWakeUpAnimation = + !isPulsing() + && mStatusBarStateController.getDozeAmount() == 1f + && mWakefulnessLifecycle.getLastWakeReason() + == PowerManager.WAKE_REASON_POWER_BUTTON + && mFingerprintManager.get().isPowerbuttonFps() + && mFingerprintManager.get().hasEnrolledFingerprints() + && !touchToUnlockAnytime; + if (DEBUG_WAKEUP_DELAY) { + Log.d(TAG, "mShouldDelayWakeUpAnimation=" + mShouldDelayWakeUpAnimation); + } + } else { + // If we're not animating anyway, we do not need to delay it. + mShouldDelayWakeUpAnimation = false; + if (DEBUG_WAKEUP_DELAY) { + Log.d(TAG, "mShouldDelayWakeUpAnimation CLEARED"); + } + } + + mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation( + mShouldDelayWakeUpAnimation); + mWakeUpCoordinator.setWakingUp( + /* wakingUp= */ true, + mShouldDelayWakeUpAnimation); + if (!mKeyguardBypassController.getBypassEnabled()) { mHeadsUpManager.releaseAllImmediately(); } @@ -3577,7 +3630,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void onFinishedWakingUp() { mWakeUpCoordinator.setFullyAwake(true); - mWakeUpCoordinator.setWakingUp(false); + mWakeUpCoordinator.setWakingUp(false, false); if (mKeyguardStateController.isOccluded() && !mDozeParameters.canControlUnlockedScreenOff()) { // When the keyguard is occluded we don't use the KEYGUARD state which would @@ -4317,7 +4370,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mNavigationBarController.touchAutoDim(mDisplayId); Trace.beginSection("CentralSurfaces#updateKeyguardState"); if (mState == StatusBarState.KEYGUARD) { - mNotificationPanelViewController.cancelPendingPanelCollapse(); + mNotificationPanelViewController.cancelPendingCollapse(); } updateDozingState(); checkBarModes(); @@ -4450,4 +4503,15 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } return mUserTracker.getUserHandle(); } + + /** + * Whether we want to animate the wake animation AOD to lockscreen. This is done only if the + * doze service host says we can, and also we're not wake and unlocking (in which case the + * AOD instantly hides). + */ + private boolean shouldAnimateDozeWakeup() { + return mDozeServiceHost.shouldAnimateWakeup() + && mBiometricUnlockController.getMode() + != BiometricUnlockController.MODE_WAKE_AND_UNLOCK; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index 69f7c71dafba..171e3d0a864e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -32,6 +32,7 @@ import com.android.systemui.flags.Flags; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; +import com.android.systemui.shade.ShadeHeadsUpTracker; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.HeadsUpStatusBarView; @@ -133,7 +134,8 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar // has started pulling down the notification shade from the HUN and then the font size // changes). We need to re-fetch these values since they're used to correctly display the // HUN during this shade expansion. - mTrackedChild = notificationPanelViewController.getTrackedHeadsUpNotification(); + mTrackedChild = notificationPanelViewController.getShadeHeadsUpTracker() + .getTrackedHeadsUpNotification(); mAppearFraction = stackScrollerController.getAppearFraction(); mExpandedHeight = stackScrollerController.getExpandedHeight(); @@ -170,19 +172,23 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar mView.setOnDrawingRectChangedListener( () -> updateIsolatedIconLocation(true /* requireUpdate */)); mWakeUpCoordinator.addListener(this); - mNotificationPanelViewController.addTrackingHeadsUpListener(mSetTrackingHeadsUp); - mNotificationPanelViewController.setHeadsUpAppearanceController(this); + getShadeHeadsUpTracker().addTrackingHeadsUpListener(mSetTrackingHeadsUp); + getShadeHeadsUpTracker().setHeadsUpAppearanceController(this); mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight); mDarkIconDispatcher.addDarkReceiver(this); } + private ShadeHeadsUpTracker getShadeHeadsUpTracker() { + return mNotificationPanelViewController.getShadeHeadsUpTracker(); + } + @Override protected void onViewDetached() { mHeadsUpManager.removeListener(this); mView.setOnDrawingRectChangedListener(null); mWakeUpCoordinator.removeListener(this); - mNotificationPanelViewController.removeTrackingHeadsUpListener(mSetTrackingHeadsUp); - mNotificationPanelViewController.setHeadsUpAppearanceController(null); + getShadeHeadsUpTracker().removeTrackingHeadsUpListener(mSetTrackingHeadsUp); + getShadeHeadsUpTracker().setHeadsUpAppearanceController(null); mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight); mDarkIconDispatcher.removeDarkReceiver(this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 3743fff3aaf7..1a84dde0384c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -271,13 +271,15 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, } /** - * Sets whether an entry's menu row is exposed and therefore it should stick in the heads up + * Sets whether an entry's guts are exposed and therefore it should stick in the heads up * area if it's pinned until it's hidden again. */ - public void setMenuShown(@NonNull NotificationEntry entry, boolean menuShown) { + public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) { HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey()); - if (headsUpEntry instanceof HeadsUpEntryPhone && entry.isRowPinned()) { - ((HeadsUpEntryPhone) headsUpEntry).setMenuShownPinned(menuShown); + if (!(headsUpEntry instanceof HeadsUpEntryPhone)) return; + HeadsUpEntryPhone headsUpEntryPhone = (HeadsUpEntryPhone)headsUpEntry; + if (entry.isRowPinned() || !gutsShown) { + headsUpEntryPhone.setGutsShownPinned(gutsShown); } } @@ -411,7 +413,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, protected class HeadsUpEntryPhone extends HeadsUpManager.HeadsUpEntry { - private boolean mMenuShownPinned; + private boolean mGutsShownPinned; /** * If the time this entry has been on was extended @@ -421,7 +423,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, @Override public boolean isSticky() { - return super.isSticky() || mMenuShownPinned; + return super.isSticky() || mGutsShownPinned; } public void setEntry(@NonNull final NotificationEntry entry) { @@ -469,13 +471,13 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, } } - public void setMenuShownPinned(boolean menuShownPinned) { - if (mMenuShownPinned == menuShownPinned) { + public void setGutsShownPinned(boolean gutsShownPinned) { + if (mGutsShownPinned == gutsShownPinned) { return; } - mMenuShownPinned = menuShownPinned; - if (menuShownPinned) { + mGutsShownPinned = gutsShownPinned; + if (gutsShownPinned) { removeAutoRemovalCallbacks(); } else { updateEntry(false /* updatePostTime */); @@ -485,7 +487,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, @Override public void reset() { super.reset(); - mMenuShownPinned = false; + mGutsShownPinned = false; extended = false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index fe2a9137c1a9..534edb97bc5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -88,6 +88,8 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private boolean mDirectReplying; private boolean mNavbarColorManagedByIme; + private boolean mIsCustomizingForBackNav; + @Inject public LightBarController( Context ctx, @@ -137,16 +139,17 @@ public class LightBarController implements BatteryController.BatteryStateChangeC for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) { stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]); } - if (stackAppearancesChanged || sbModeChanged) { + if (stackAppearancesChanged || sbModeChanged || mIsCustomizingForBackNav) { mAppearanceRegions = appearanceRegions; onStatusBarModeChanged(statusBarMode); + mIsCustomizingForBackNav = false; } mNavbarColorManagedByIme = navbarColorManagedByIme; } void onStatusBarModeChanged(int newBarMode) { mStatusBarMode = newBarMode; - updateStatus(); + updateStatus(mAppearanceRegions); } public void onNavigationBarAppearanceChanged(@Appearance int appearance, boolean nbModeChanged, @@ -186,6 +189,31 @@ public class LightBarController implements BatteryController.BatteryStateChangeC } /** + * Controls the light status bar temporarily for back navigation. + * @param appearance the custmoized appearance. + */ + public void customizeStatusBarAppearance(AppearanceRegion appearance) { + if (appearance != null) { + final ArrayList<AppearanceRegion> appearancesList = new ArrayList<>(); + appearancesList.add(appearance); + for (int i = 0; i < mAppearanceRegions.length; i++) { + final AppearanceRegion ar = mAppearanceRegions[i]; + if (appearance.getBounds().contains(ar.getBounds())) { + continue; + } + appearancesList.add(ar); + } + + final AppearanceRegion[] newAppearances = new AppearanceRegion[appearancesList.size()]; + updateStatus(appearancesList.toArray(newAppearances)); + mIsCustomizingForBackNav = true; + } else { + mIsCustomizingForBackNav = false; + updateStatus(mAppearanceRegions); + } + } + + /** * Sets whether the direct-reply is in use or not. * @param directReplying {@code true} when the direct-reply is in-use. */ @@ -226,12 +254,12 @@ public class LightBarController implements BatteryController.BatteryStateChangeC && unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK; } - private void updateStatus() { - final int numStacks = mAppearanceRegions.length; + private void updateStatus(AppearanceRegion[] appearanceRegions) { + final int numStacks = appearanceRegions.length; final ArrayList<Rect> lightBarBounds = new ArrayList<>(); for (int i = 0; i < numStacks; i++) { - final AppearanceRegion ar = mAppearanceRegions[i]; + final AppearanceRegion ar = appearanceRegions[i]; if (isLight(ar.getAppearance(), mStatusBarMode, APPEARANCE_LIGHT_STATUS_BARS)) { lightBarBounds.add(ar.getBounds()); } @@ -247,7 +275,6 @@ public class LightBarController implements BatteryController.BatteryStateChangeC else if (lightBarBounds.size() == numStacks) { mStatusBarIconController.setIconsDarkArea(null); mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange()); - } // Not the same for every stack, magic! diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 4ee2de11abdf..006a029de8e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -136,11 +136,13 @@ public class NotificationIconContainer extends ViewGroup { } }.setDuration(CONTENT_FADE_DURATION); - private static final int MAX_ICONS_ON_AOD = 3; + /* Maximum number of icons on AOD when also showing overflow dot. */ + private int mMaxIconsOnAod; /* Maximum number of icons in short shelf on lockscreen when also showing overflow dot. */ - public static final int MAX_ICONS_ON_LOCKSCREEN = 3; - public static final int MAX_STATIC_ICONS = 4; + private int mMaxIconsOnLockscreen; + /* Maximum number of icons in the status bar when also showing overflow dot. */ + private int mMaxStaticIcons; private boolean mIsStaticLayout = true; private final HashMap<View, IconState> mIconStates = new HashMap<>(); @@ -174,14 +176,19 @@ public class NotificationIconContainer extends ViewGroup { public NotificationIconContainer(Context context, AttributeSet attrs) { super(context, attrs); - initDimens(); + initResources(); setWillNotDraw(!(DEBUG || DEBUG_OVERFLOW)); } - private void initDimens() { + private void initResources() { + mMaxIconsOnAod = getResources().getInteger(R.integer.max_notif_icons_on_aod); + mMaxIconsOnLockscreen = getResources().getInteger(R.integer.max_notif_icons_on_lockscreen); + mMaxStaticIcons = getResources().getInteger(R.integer.max_notif_static_icons); + mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding); mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius); mStaticDotDiameter = 2 * mStaticDotRadius; + final Context themedContext = new ContextThemeWrapper(getContext(), com.android.internal.R.style.Theme_DeviceDefault_DayNight); mThemedTextColorPrimary = Utils.getColorAttr(themedContext, @@ -225,7 +232,7 @@ public class NotificationIconContainer extends ViewGroup { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - initDimens(); + initResources(); } @Override @@ -424,7 +431,7 @@ public class NotificationIconContainer extends ViewGroup { return 0f; } final float contentWidth = - mIconSize * MathUtils.min(numIcons, MAX_ICONS_ON_LOCKSCREEN + 1); + mIconSize * MathUtils.min(numIcons, mMaxIconsOnLockscreen + 1); return getActualPaddingStart() + contentWidth + getActualPaddingEnd(); @@ -539,8 +546,8 @@ public class NotificationIconContainer extends ViewGroup { } private int getMaxVisibleIcons(int childCount) { - return mOnLockScreen ? MAX_ICONS_ON_AOD : - mIsStaticLayout ? MAX_STATIC_ICONS : childCount; + return mOnLockScreen ? mMaxIconsOnAod : + mIsStaticLayout ? mMaxStaticIcons : childCount; } private float getLayoutEnd() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java index 3d6bebbe998c..a7413d58a6cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java @@ -65,18 +65,7 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener mNotificationShadeWindowController.setHeadsUpShowing(true); mStatusBarWindowController.setForceStatusBarVisible(true); if (mNotificationPanelViewController.isFullyCollapsed()) { - // We need to ensure that the touchable region is updated before the - //window will be - // resized, in order to not catch any touches. A layout will ensure that - // onComputeInternalInsets will be called and after that we can - //resize the layout. Let's - // make sure that the window stays small for one frame until the - //touchableRegion is set. - mNotificationPanelViewController.requestLayoutOnView(); - mNotificationShadeWindowController.setForceWindowCollapsed(true); - mNotificationPanelViewController.postToView(() -> { - mNotificationShadeWindowController.setForceWindowCollapsed(false); - }); + mNotificationPanelViewController.updateTouchableRegion(); } } else { boolean bypassKeyguard = mKeyguardBypassController.getBypassEnabled() @@ -96,7 +85,8 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener //animation // is finished. mHeadsUpManager.setHeadsUpGoingAway(true); - mNotificationPanelViewController.runAfterAnimationFinished(() -> { + mNotificationPanelViewController.getNotificationStackScrollLayoutController() + .runAfterAnimationFinished(() -> { if (!mHeadsUpManager.hasPinnedHeadsUp()) { mNotificationShadeWindowController.setHeadsUpShowing(false); mHeadsUpManager.setHeadsUpGoingAway(false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index f06b5db84588..49b58df23fdb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -281,7 +281,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastScreenOffAnimationPlaying; private float mQsExpansion; final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>(); - private boolean mIsModernAlternateBouncerEnabled; private boolean mIsBackAnimationEnabled; private final boolean mUdfpsNewTouchDetectionEnabled; private final UdfpsOverlayInteractor mUdfpsOverlayInteractor; @@ -363,7 +362,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mPrimaryBouncerView = primaryBouncerView; mFoldAodAnimationController = sysUIUnfoldComponent .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null); - mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER); mAlternateBouncerInteractor = alternateBouncerInteractor; mIsBackAnimationEnabled = featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM); @@ -395,35 +393,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb registerListeners(); } - /** - * Sets the given legacy alternate bouncer to null if it's the current alternate bouncer. Else, - * does nothing. Only used if modern alternate bouncer is NOT enabled. - */ - public void removeLegacyAlternateBouncer( - @NonNull LegacyAlternateBouncer alternateBouncerLegacy) { - if (!mIsModernAlternateBouncerEnabled) { - if (Objects.equals(mAlternateBouncerInteractor.getLegacyAlternateBouncer(), - alternateBouncerLegacy)) { - mAlternateBouncerInteractor.setLegacyAlternateBouncer(null); - hideAlternateBouncer(true); - } - } - } - - /** - * Sets a new legacy alternate bouncer. Only used if modern alternate bouncer is NOT enabled. - */ - public void setLegacyAlternateBouncer(@NonNull LegacyAlternateBouncer alternateBouncerLegacy) { - if (!mIsModernAlternateBouncerEnabled) { - if (!Objects.equals(mAlternateBouncerInteractor.getLegacyAlternateBouncer(), - alternateBouncerLegacy)) { - mAlternateBouncerInteractor.setLegacyAlternateBouncer(alternateBouncerLegacy); - hideAlternateBouncer(true); - } - } - - } - /** * Sets the given OccludingAppBiometricUI to null if it's the current auth interceptor. Else, @@ -1004,7 +973,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void onKeyguardFadedAway() { mNotificationContainer.postDelayed(() -> mNotificationShadeWindowController .setKeyguardFadingAway(false), 100); - mNotificationPanelViewController.resetViewAlphas(); + mNotificationPanelViewController.resetViewGroupFade(); mCentralSurfaces.finishKeyguardFadingAway(); mBiometricUnlockController.finishKeyguardFadingAway(); WindowManagerGlobal.getInstance().trimMemory( @@ -1079,7 +1048,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (hideImmediately) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(false); } else { - mNotificationPanelViewController.expandShadeToNotifications(); + mNotificationPanelViewController.expandToNotifications(); } } return; @@ -1386,7 +1355,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void dump(PrintWriter pw) { pw.println("StatusBarKeyguardViewManager:"); - pw.println(" mIsModernAlternateBouncerEnabled: " + mIsModernAlternateBouncerEnabled); pw.println(" mRemoteInputActive: " + mRemoteInputActive); pw.println(" mDozing: " + mDozing); pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction); @@ -1585,28 +1553,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** - * @deprecated Delegate used to send show and hide events to an alternate bouncer. - */ - public interface LegacyAlternateBouncer { - /** - * Show alternate authentication bouncer. - * @return whether alternate auth method was newly shown - */ - boolean showAlternateBouncer(); - - /** - * Hide alternate authentication bouncer - * @return whether the alternate auth method was newly hidden - */ - boolean hideAlternateBouncer(); - - /** - * @return true if the alternate auth bouncer is showing - */ - boolean isShowingAlternateBouncer(); - } - - /** * Delegate used to send show and hide events to an alternate authentication method instead of * the regular pin/pattern/password bouncer. */ 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 4eed48739b40..39362cf29e14 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.statusbar.phone.CentralSurfaces.CLOSE_PANEL_WHEN_EMPTIED; import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG; -import static com.android.systemui.statusbar.phone.CentralSurfaces.MULTIUSER_DEBUG; import android.app.KeyguardManager; import android.content.Context; @@ -176,7 +175,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, } remoteInputManager.setUpWithCallback( remoteInputManagerCallback, - mNotificationPanel.createRemoteInputDelegate()); + mNotificationPanel.getShadeNotificationPresenter().createRemoteInputDelegate()); initController.addPostInitTask(() -> { mKeyguardIndicationController.init(); @@ -209,8 +208,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter, } private void maybeEndAmbientPulse() { - if (mNotificationPanel.hasPulsingNotifications() && - !mHeadsUpManager.hasNotifications()) { + if (mNotificationPanel.getShadeNotificationPresenter().hasPulsingNotifications() + && !mHeadsUpManager.hasNotifications()) { // We were showing a pulse for a notification, but no notifications are pulsing anymore. // Finish the pulse. mDozeScrimController.pulseOutNow(); @@ -222,7 +221,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, // Begin old BaseStatusBar.userSwitched mHeadsUpManager.setUser(newUserId); // End old BaseStatusBar.userSwitched - if (MULTIUSER_DEBUG) mNotificationPanel.setHeaderDebugInfo("USER " + newUserId); mCommandQueue.animateCollapsePanels(); mMediaManager.clearCurrentMediaNotification(); mCentralSurfaces.setLockscreenUser(newUserId); @@ -243,7 +241,9 @@ class StatusBarNotificationPresenter implements NotificationPresenter, @Override public void onActivated(ActivatableNotificationView view) { onActivated(); - if (view != null) mNotificationPanel.setActivatedChild(view); + if (view != null) { + mNotificationPanel.getShadeNotificationPresenter().setActivatedChild(view); + } } public void onActivated() { @@ -251,7 +251,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter, MetricsEvent.ACTION_LS_NOTE, 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH); - ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild(); + ActivatableNotificationView previousView = + mNotificationPanel.getShadeNotificationPresenter().getActivatedChild(); if (previousView != null) { previousView.makeInactive(true /* animate */); } @@ -259,8 +260,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter, @Override public void onActivationReset(ActivatableNotificationView view) { - if (view == mNotificationPanel.getActivatedChild()) { - mNotificationPanel.setActivatedChild(null); + if (view == mNotificationPanel.getShadeNotificationPresenter().getActivatedChild()) { + mNotificationPanel.getShadeNotificationPresenter().setActivatedChild(null); mKeyguardIndicationController.hideTransientIndication(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index 53e08ea8e10d..118bfc55dd4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -14,6 +14,7 @@ import android.view.WindowManager.fixScale import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD +import com.android.systemui.DejankUtils import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.KeyguardViewMediator @@ -27,6 +28,7 @@ import com.android.systemui.statusbar.notification.PropertyAnimator import com.android.systemui.statusbar.notification.stack.AnimationProperties import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.TraceUtils import com.android.systemui.util.settings.GlobalSettings import javax.inject.Inject @@ -116,6 +118,11 @@ class UnlockedScreenOffAnimationController @Inject constructor( }) } + // FrameCallback used to delay starting the light reveal animation until the next frame + private val startLightRevealCallback = TraceUtils.namedRunnable("startLightReveal") { + lightRevealAnimator.start() + } + val animatorDurationScaleObserver = object : ContentObserver(null) { override fun onChange(selfChange: Boolean) { updateAnimatorDurationScale() @@ -223,6 +230,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( decidedToAnimateGoingToSleep = null shouldAnimateInKeyguard = false + DejankUtils.removeCallbacks(startLightRevealCallback) lightRevealAnimator.cancel() handler.removeCallbacksAndMessages(null) } @@ -253,7 +261,14 @@ class UnlockedScreenOffAnimationController @Inject constructor( shouldAnimateInKeyguard = true lightRevealAnimationPlaying = true - lightRevealAnimator.start() + + // Start the animation on the next frame. startAnimation() is called after + // PhoneWindowManager makes a binder call to System UI on + // IKeyguardService#onStartedGoingToSleep(). By the time we get here, system_server is + // already busy making changes to PowerManager and DisplayManager. This increases our + // chance of missing the first frame, so to mitigate this we should start the animation + // on the next frame. + DejankUtils.postAfterTraversal(startLightRevealCallback) handler.postDelayed({ // Only run this callback if the device is sleeping (not interactive). This callback // is removed in onStartedWakingUp, but since that event is asynchronously diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index 24ddded8847a..fe639943e191 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -509,7 +509,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private boolean shouldHideNotificationIcons() { if (!mShadeExpansionStateManager.isClosed() - && mNotificationPanelViewController.hideStatusBarIconsWhenExpanded()) { + && mNotificationPanelViewController.shouldHideStatusBarIconsWhenExpanded()) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt index adfea80715a2..eaa145582ba3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt @@ -37,6 +37,8 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIc import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxyImpl +import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy +import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxyImpl import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository @@ -65,8 +67,7 @@ abstract class StatusBarPipelineModule { @Binds abstract fun wifiRepository(impl: WifiRepositorySwitcher): WifiRepository - @Binds - abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor + @Binds abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor @Binds abstract fun mobileConnectionsRepository( @@ -78,6 +79,11 @@ abstract class StatusBarPipelineModule { @Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy @Binds + abstract fun subscriptionManagerProxy( + impl: SubscriptionManagerProxyImpl + ): SubscriptionManagerProxy + + @Binds abstract fun mobileIconsInteractor(impl: MobileIconsInteractorImpl): MobileIconsInteractor @Binds diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index 8c93bf7c2198..45d50c103909 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -44,6 +44,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy +import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel @@ -65,6 +66,7 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext @@ -76,6 +78,7 @@ class MobileConnectionsRepositoryImpl constructor( connectivityRepository: ConnectivityRepository, private val subscriptionManager: SubscriptionManager, + private val subscriptionManagerProxy: SubscriptionManagerProxy, private val telephonyManager: TelephonyManager, private val logger: MobileInputLogger, @MobileSummaryLog private val tableLogger: TableLogBuffer, @@ -195,7 +198,7 @@ constructor( override val defaultDataSubId: StateFlow<Int> = broadcastDispatcher .broadcastFlow( - IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED) + IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED), ) { intent, _ -> intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID) } @@ -204,14 +207,11 @@ constructor( tableLogger, LOGGING_PREFIX, columnName = "defaultSubId", - initialValue = SubscriptionManager.getDefaultDataSubscriptionId(), + initialValue = INVALID_SUBSCRIPTION_ID, ) + .onStart { emit(subscriptionManagerProxy.getDefaultDataSubscriptionId()) } .onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) } - .stateIn( - scope, - SharingStarted.WhileSubscribed(), - SubscriptionManager.getDefaultDataSubscriptionId() - ) + .stateIn(scope, SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID) private val carrierConfigChangedEvent = broadcastDispatcher diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/util/SubscriptionManagerProxy.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/util/SubscriptionManagerProxy.kt new file mode 100644 index 000000000000..22d048343bc9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/util/SubscriptionManagerProxy.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.util + +import android.telephony.SubscriptionManager +import javax.inject.Inject + +interface SubscriptionManagerProxy { + fun getDefaultDataSubscriptionId(): Int +} + +/** Injectable proxy class for [SubscriptionManager]'s static methods */ +class SubscriptionManagerProxyImpl @Inject constructor() : SubscriptionManagerProxy { + /** The system default data subscription id, or INVALID_SUBSCRIPTION_ID on error */ + override fun getDefaultDataSubscriptionId() = SubscriptionManager.getDefaultDataSubscriptionId() +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index 86e74564fba0..a4cb99b1b94b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -64,7 +64,7 @@ public class BrightnessMirrorController mToggleSliderController = setMirrorLayout(); mNotificationPanel = notificationPanelViewController; mDepthController = notificationShadeDepthController; - mNotificationPanel.setPanelAlphaEndAction(() -> { + mNotificationPanel.setAlphaChangeAnimationEndAction(() -> { mBrightnessMirror.setVisibility(View.INVISIBLE); }); mVisibilityCallback = visibilityCallback; @@ -74,13 +74,13 @@ public class BrightnessMirrorController public void showMirror() { mBrightnessMirror.setVisibility(View.VISIBLE); mVisibilityCallback.accept(true); - mNotificationPanel.setPanelAlpha(0, true /* animate */); + mNotificationPanel.setAlpha(0, true /* animate */); mDepthController.setBrightnessMirrorVisible(true); } public void hideMirror() { mVisibilityCallback.accept(false); - mNotificationPanel.setPanelAlpha(255, true /* animate */); + mNotificationPanel.setAlpha(255, true /* animate */); mDepthController.setBrightnessMirrorVisible(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt index 32c64f457501..8c61ada3f8ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt @@ -36,6 +36,7 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.settings.UserTracker import com.android.systemui.util.settings.GlobalSettings import com.android.systemui.util.settings.SecureSettings +import com.android.systemui.util.wrapper.BuildInfo import java.io.PrintWriter import java.util.concurrent.Executor import java.util.concurrent.atomic.AtomicBoolean @@ -47,6 +48,7 @@ open class DeviceProvisionedControllerImpl @Inject constructor( private val globalSettings: GlobalSettings, private val userTracker: UserTracker, private val dumpManager: DumpManager, + private val buildInfo: BuildInfo, @Background private val backgroundHandler: Handler, @Main private val mainExecutor: Executor ) : DeviceProvisionedController, @@ -187,7 +189,7 @@ open class DeviceProvisionedControllerImpl @Inject constructor( } override fun isFrpActive(): Boolean { - return frpActive.get() + return frpActive.get() && !buildInfo.isDebuggable } override fun isUserSetup(user: Int): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index 1a4a311ee0de..9ede6ce29963 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -281,6 +281,10 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { mUser = user; } + public int getUser() { + return mUser; + } + public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println("HeadsUpManager state:"); dumpInternal(pw, args); diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java index f09b2f76e38c..757b4e50c3f8 100644 --- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java +++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java @@ -108,13 +108,18 @@ public class TouchInsetManager { private void updateTouchRegions() { mExecutor.execute(() -> { final HashMap<AttachedSurfaceControl, Region> affectedSurfaces = new HashMap<>(); + if (mTrackedViews.isEmpty()) { + return; + } + mTrackedViews.stream().forEach(view -> { - if (!view.isAttachedToWindow()) { + final AttachedSurfaceControl surface = view.getRootSurfaceControl(); + + // Detached views will not have a surface control. + if (surface == null) { return; } - final AttachedSurfaceControl surface = view.getRootSurfaceControl(); - if (!affectedSurfaces.containsKey(surface)) { affectedSurfaces.put(surface, Region.obtain()); } @@ -179,6 +184,7 @@ public class TouchInsetManager { mSessionRegions.values().stream().forEach(regionMapping -> { regionMapping.entrySet().stream().forEach(entry -> { final AttachedSurfaceControl surface = entry.getKey(); + if (!affectedSurfaces.containsKey(surface)) { affectedSurfaces.put(surface, Region.obtain()); } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt index 101bd4483cb3..d1bd73a4fa5a 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt @@ -30,6 +30,7 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.shade.ShadeFoldAnimator import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.ScreenOffAnimation @@ -79,7 +80,7 @@ constructor( private val foldToAodLatencyTracker = FoldToAodLatencyTracker() private val startAnimationRunnable = Runnable { - centralSurfaces.notificationPanelViewController.startFoldToAodAnimation( + getShadeFoldAnimator().startFoldToAodAnimation( /* startAction= */ { foldToAodLatencyTracker.onAnimationStarted() }, /* endAction= */ { setAnimationState(playing = false) }, /* cancelAction= */ { setAnimationState(playing = false) }, @@ -93,7 +94,7 @@ constructor( wakefulnessLifecycle.addObserver(this) // TODO(b/254878364): remove this call to NPVC.getView() - centralSurfaces.notificationPanelViewController.view.repeatWhenAttached { + getShadeFoldAnimator().view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { listenForDozing(this) } } } @@ -109,7 +110,7 @@ constructor( override fun startAnimation(): Boolean = if (shouldStartAnimation()) { setAnimationState(playing = true) - centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation() + getShadeFoldAnimator().prepareFoldToAodAnimation() true } else { setAnimationState(playing = false) @@ -120,12 +121,15 @@ constructor( if (isAnimationPlaying) { foldToAodLatencyTracker.cancel() cancelAnimation?.run() - centralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation() + getShadeFoldAnimator().cancelFoldToAodAnimation() } setAnimationState(playing = false) } + private fun getShadeFoldAnimator(): ShadeFoldAnimator = + centralSurfaces.notificationPanelViewController.shadeFoldAnimator + private fun setAnimationState(playing: Boolean) { shouldPlayAnimation = playing isAnimationPlaying = playing @@ -152,16 +156,17 @@ constructor( } else if (isFolded && !isFoldHandled && alwaysOnEnabled && isDozing) { // Screen turning on for the first time after folding and we are already dozing // We should play the folding to AOD animation + isFoldHandled = true setAnimationState(playing = true) - centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation() + getShadeFoldAnimator().prepareFoldToAodAnimation() // We don't need to wait for the scrim as it is already displayed // but we should wait for the initial animation preparations to be drawn // (setting initial alpha/translation) // TODO(b/254878364): remove this call to NPVC.getView() OneShotPreDrawListener.add( - centralSurfaces.notificationPanelViewController.view, + getShadeFoldAnimator().view, onReady ) } else { @@ -186,7 +191,10 @@ constructor( cancelAnimation?.run() // Post starting the animation to the next frame to avoid junk due to inset changes - cancelAnimation = mainExecutor.executeDelayed(startAnimationRunnable, /* delayMillis= */ 0) + cancelAnimation = mainExecutor.executeDelayed( + startAnimationRunnable, + /* delayMillis= */ 0 + ) shouldPlayAnimation = false } } diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java index f7c8bac1b478..b2bf9727b534 100644 --- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java +++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java @@ -16,7 +16,6 @@ package com.android.systemui.user; -import android.app.Activity; import android.os.UserHandle; import com.android.settingslib.users.EditUserInfoController; @@ -24,11 +23,8 @@ import com.android.systemui.user.data.repository.UserRepositoryModule; import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule; import com.android.systemui.user.ui.dialog.UserDialogModule; -import dagger.Binds; import dagger.Module; import dagger.Provides; -import dagger.multibindings.ClassKey; -import dagger.multibindings.IntoMap; /** * Dagger module for User related classes. @@ -49,12 +45,6 @@ public abstract class UserModule { return new EditUserInfoController(FILE_PROVIDER_AUTHORITY); } - /** Provides UserSwitcherActivity */ - @Binds - @IntoMap - @ClassKey(UserSwitcherActivity.class) - public abstract Activity provideUserSwitcherActivity(UserSwitcherActivity activity); - /** * Provides the {@link UserHandle} for the user associated with this System UI process. * diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt deleted file mode 100644 index 52b7fb63c1a2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.user - -import android.os.Bundle -import android.view.WindowInsets.Type -import android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE -import androidx.activity.ComponentActivity -import androidx.lifecycle.ViewModelProvider -import com.android.systemui.R -import com.android.systemui.classifier.FalsingCollector -import com.android.systemui.user.ui.binder.UserSwitcherViewBinder -import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel -import dagger.Lazy -import javax.inject.Inject - -/** Support a fullscreen user switcher */ -open class UserSwitcherActivity -@Inject -constructor( - private val falsingCollector: FalsingCollector, - private val viewModelFactory: Lazy<UserSwitcherViewModel.Factory>, -) : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.user_switcher_fullscreen) - window.decorView.windowInsetsController?.let { controller -> - controller.systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - controller.hide(Type.systemBars()) - } - val viewModel = - ViewModelProvider(this, viewModelFactory.get())[UserSwitcherViewModel::class.java] - UserSwitcherViewBinder.bind( - view = requireViewById(R.id.user_switcher_root), - viewModel = viewModel, - lifecycleOwner = this, - layoutInflater = layoutInflater, - falsingCollector = falsingCollector, - onFinish = this::finish, - ) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt new file mode 100644 index 000000000000..72786efc416d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.user + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.WindowInsets +import android.view.WindowInsetsController +import com.android.systemui.R +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.user.ui.binder.UserSwitcherViewBinder +import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel + +class UserSwitchFullscreenDialog( + context: Context, + private val falsingCollector: FalsingCollector, + private val userSwitcherViewModel: UserSwitcherViewModel, +) : SystemUIDialog(context, R.style.Theme_UserSwitcherFullscreenDialog) { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setShowForAllUsers(true) + setCanceledOnTouchOutside(true) + + window?.decorView?.windowInsetsController?.let { controller -> + controller.systemBarsBehavior = + WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + controller.hide(WindowInsets.Type.systemBars()) + } + + val view = + LayoutInflater.from(this.context).inflate(R.layout.user_switcher_fullscreen, null) + setContentView(view) + + UserSwitcherViewBinder.bind( + view = requireViewById(R.id.user_switcher_root), + viewModel = userSwitcherViewModel, + layoutInflater = layoutInflater, + falsingCollector = falsingCollector, + onFinish = this::dismiss, + ) + } + + override fun getWidth(): Int { + val displayMetrics = context.resources.displayMetrics.apply { + context.display.getRealMetrics(this) + } + return displayMetrics.widthPixels + } + + override fun getHeight() = MATCH_PARENT + +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index 94dd1b309436..0ec1a214660c 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -49,7 +49,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.user.UserSwitchDialogController import com.android.systemui.telephony.domain.interactor.TelephonyInteractor -import com.android.systemui.user.UserSwitcherActivity import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.user.data.source.UserRecord @@ -513,24 +512,12 @@ constructor( } } - fun showUserSwitcher(context: Context, expandable: Expandable) { - if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) { + fun showUserSwitcher(expandable: Expandable) { + if (featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) { + showDialog(ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog(expandable)) + } else { showDialog(ShowDialogRequestModel.ShowUserSwitcherDialog(expandable)) - return } - - val intent = - Intent(context, UserSwitcherActivity::class.java).apply { - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) - } - - activityStarter.startActivity( - intent, - true /* dismissShade */, - expandable.activityLaunchController(), - true /* showOverlockscreenwhenlocked */, - UserHandle.SYSTEM, - ) } private fun showDialog(request: ShowDialogRequestModel) { diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt index 14cc3e783fed..de73cdbb6026 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt @@ -50,4 +50,8 @@ sealed class ShowDialogRequestModel( data class ShowUserSwitcherDialog( override val expandable: Expandable?, ) : ShowDialogRequestModel() + + data class ShowUserSwitcherFullscreenDialog( + override val expandable: Expandable?, + ) : ShowDialogRequestModel() } diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt index e13710786fbb..7236e0fd134a 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt @@ -31,19 +31,18 @@ import android.widget.TextView import androidx.constraintlayout.helper.widget.Flow as FlowWidget import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.Gefingerpoken import com.android.systemui.R import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.user.UserSwitcherPopupMenu import com.android.systemui.user.UserSwitcherRootView import com.android.systemui.user.shared.model.UserActionModel import com.android.systemui.user.ui.viewmodel.UserActionViewModel import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel import com.android.systemui.util.children -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @@ -56,7 +55,6 @@ object UserSwitcherViewBinder { fun bind( view: ViewGroup, viewModel: UserSwitcherViewModel, - lifecycleOwner: LifecycleOwner, layoutInflater: LayoutInflater, falsingCollector: FalsingCollector, onFinish: () -> Unit, @@ -79,88 +77,92 @@ object UserSwitcherViewBinder { addButton.setOnClickListener { viewModel.onOpenMenuButtonClicked() } cancelButton.setOnClickListener { viewModel.onCancelButtonClicked() } - lifecycleOwner.lifecycleScope.launch { - lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { - launch { - viewModel.isFinishRequested - .filter { it } - .collect { - onFinish() - viewModel.onFinished() - } + view.repeatWhenAttached { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + launch { + viewModel.isFinishRequested + .filter { it } + .collect { + //finish requested, we want to dismiss popupmenu at the same time + popupMenu?.dismiss() + onFinish() + viewModel.onFinished() + } + } } } - } - lifecycleOwner.lifecycleScope.launch { - lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { - launch { viewModel.isOpenMenuButtonVisible.collect { addButton.isVisible = it } } - - launch { - viewModel.isMenuVisible.collect { isVisible -> - if (isVisible && popupMenu?.isShowing != true) { - popupMenu?.dismiss() - // Use post to make sure we show the popup menu *after* the activity is - // ready to show one to avoid a WindowManager$BadTokenException. - view.post { - popupMenu = - createAndShowPopupMenu( - context = view.context, - anchorView = addButton, - adapter = popupMenuAdapter, - onDismissed = viewModel::onMenuClosed, - ) + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { viewModel.isOpenMenuButtonVisible.collect { addButton.isVisible = it } } + + launch { + viewModel.isMenuVisible.collect { isVisible -> + if (isVisible && popupMenu?.isShowing != true) { + popupMenu?.dismiss() + // Use post to make sure we show the popup menu *after* the activity is + // ready to show one to avoid a WindowManager$BadTokenException. + view.post { + popupMenu = + createAndShowPopupMenu( + context = view.context, + anchorView = addButton, + adapter = popupMenuAdapter, + onDismissed = viewModel::onMenuClosed, + ) + } + } else if (!isVisible && popupMenu?.isShowing == true) { + popupMenu?.dismiss() + popupMenu = null } - } else if (!isVisible && popupMenu?.isShowing == true) { - popupMenu?.dismiss() - popupMenu = null } } - } - launch { - viewModel.menu.collect { menuViewModels -> - popupMenuAdapter.setItems(menuViewModels) + launch { + viewModel.menu.collect { menuViewModels -> + popupMenuAdapter.setItems(menuViewModels) + } } - } - launch { - viewModel.maximumUserColumns.collect { maximumColumns -> - flowWidget.setMaxElementsWrap(maximumColumns) + launch { + viewModel.maximumUserColumns.collect { maximumColumns -> + flowWidget.setMaxElementsWrap(maximumColumns) + } } - } - launch { - viewModel.users.collect { users -> - val viewPool = - gridContainerView.children - .filter { it.tag == USER_VIEW_TAG } - .toMutableList() - viewPool.forEach { - gridContainerView.removeView(it) - flowWidget.removeView(it) - } - users.forEach { userViewModel -> - val userView = - if (viewPool.isNotEmpty()) { - viewPool.removeAt(0) - } else { - val inflatedView = - layoutInflater.inflate( - R.layout.user_switcher_fullscreen_item, - view, - false, - ) - inflatedView.tag = USER_VIEW_TAG - inflatedView - } - userView.id = View.generateViewId() - gridContainerView.addView(userView) - flowWidget.addView(userView) - UserViewBinder.bind( - view = userView, - viewModel = userViewModel, - ) + launch { + viewModel.users.collect { users -> + val viewPool = + gridContainerView.children + .filter { it.tag == USER_VIEW_TAG } + .toMutableList() + viewPool.forEach { + gridContainerView.removeView(it) + flowWidget.removeView(it) + } + users.forEach { userViewModel -> + val userView = + if (viewPool.isNotEmpty()) { + viewPool.removeAt(0) + } else { + val inflatedView = + layoutInflater.inflate( + R.layout.user_switcher_fullscreen_item, + view, + false, + ) + inflatedView.tag = USER_VIEW_TAG + inflatedView + } + userView.id = View.generateViewId() + gridContainerView.addView(userView) + flowWidget.addView(userView) + UserViewBinder.bind( + view = userView, + viewModel = userViewModel, + ) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt index 79721b370c21..0930cb8a3d7a 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt @@ -26,13 +26,16 @@ import com.android.systemui.CoreStartable import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.broadcast.BroadcastSender +import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.tiles.UserDetailView +import com.android.systemui.user.UserSwitchFullscreenDialog import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.user.domain.model.ShowDialogRequestModel +import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel import dagger.Lazy import javax.inject.Inject import javax.inject.Provider @@ -54,6 +57,8 @@ constructor( private val userDetailAdapterProvider: Provider<UserDetailView.Adapter>, private val eventLogger: Lazy<UiEventLogger>, private val activityStarter: Lazy<ActivityStarter>, + private val falsingCollector: Lazy<FalsingCollector>, + private val userSwitcherViewModel: Lazy<UserSwitcherViewModel>, ) : CoreStartable { private var currentDialog: Dialog? = null @@ -124,6 +129,15 @@ constructor( INTERACTION_JANK_EXIT_GUEST_MODE_TAG, ), ) + is ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog -> + Pair( + UserSwitchFullscreenDialog( + context = context.get(), + falsingCollector = falsingCollector.get(), + userSwitcherViewModel = userSwitcherViewModel.get(), + ), + null, /* dialogCuj */ + ) } currentDialog = dialog diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt index 3300e8e5b2a5..78edad7c3af2 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt @@ -55,5 +55,5 @@ constructor( interactor.selectedUser.mapLatest { userModel -> userModel.image } /** Action to execute on click. Should launch the user switcher */ - val onClick: (Expandable) -> Unit = { interactor.showUserSwitcher(context, it) } + val onClick: (Expandable) -> Unit = { interactor.showUserSwitcher(it) } } diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt index 37115ad53880..afd72e7ed1be 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt @@ -17,12 +17,10 @@ package com.android.systemui.user.ui.viewmodel -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import com.android.systemui.R import com.android.systemui.common.shared.model.Text import com.android.systemui.common.ui.drawable.CircularDrawable -import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.user.domain.interactor.GuestUserInteractor import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper @@ -36,12 +34,13 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map /** Models UI state for the user switcher feature. */ +@SysUISingleton class UserSwitcherViewModel -private constructor( +@Inject +constructor( private val userInteractor: UserInteractor, private val guestUserInteractor: GuestUserInteractor, - private val powerInteractor: PowerInteractor, -) : ViewModel() { +) { /** On-device users. */ val users: Flow<List<UserViewModel>> = @@ -112,34 +111,15 @@ private constructor( } } - private fun createFinishRequestedFlow(): Flow<Boolean> { - var mostRecentSelectedUserId: Int? = null - var mostRecentIsInteractive: Boolean? = null - - return combine( - // When the user is switched, we should finish. - userInteractor.selectedUser - .map { it.id } - .map { - val selectedUserChanged = - mostRecentSelectedUserId != null && mostRecentSelectedUserId != it - mostRecentSelectedUserId = it - selectedUserChanged - }, - // When the screen turns off, we should finish. - powerInteractor.isInteractive.map { - val screenTurnedOff = mostRecentIsInteractive == true && !it - mostRecentIsInteractive = it - screenTurnedOff - }, + private fun createFinishRequestedFlow(): Flow<Boolean> = + combine( // When the cancel button is clicked, we should finish. hasCancelButtonBeenClicked, // If an executed action told us to finish, we should finish, isFinishRequiredDueToExecutedAction, - ) { selectedUserChanged, screenTurnedOff, cancelButtonClicked, executedActionFinish -> - selectedUserChanged || screenTurnedOff || cancelButtonClicked || executedActionFinish + ) { cancelButtonClicked, executedActionFinish -> + cancelButtonClicked || executedActionFinish } - } private fun toViewModel( model: UserModel, @@ -210,22 +190,4 @@ private constructor( { userInteractor.selectUser(model.id) } } } - - class Factory - @Inject - constructor( - private val userInteractor: UserInteractor, - private val guestUserInteractor: GuestUserInteractor, - private val powerInteractor: PowerInteractor, - ) : ViewModelProvider.Factory { - override fun <T : ViewModel> create(modelClass: Class<T>): T { - @Suppress("UNCHECKED_CAST") - return UserSwitcherViewModel( - userInteractor = userInteractor, - guestUserInteractor = guestUserInteractor, - powerInteractor = powerInteractor, - ) - as T - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt index b311318fb111..64234c205617 100644 --- a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt @@ -17,6 +17,7 @@ package com.android.systemui.util import android.os.Trace +import android.os.TraceNameSupplier /** * Run a block within a [Trace] section. @@ -39,5 +40,16 @@ class TraceUtils { inline fun traceRunnable(tag: String, crossinline block: () -> Unit): Runnable { return Runnable { traceSection(tag) { block() } } } + + /** + * Helper function for creating a Runnable object that implements TraceNameSupplier. + * This is useful for posting Runnables to Handlers with meaningful names. + */ + inline fun namedRunnable(tag: String, crossinline block: () -> Unit): Runnable { + return object : Runnable, TraceNameSupplier { + override fun getTraceName(): String = tag + override fun run() = block() + } + } } } diff --git a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRule2.java b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRule2.java new file mode 100644 index 000000000000..e93e86291535 --- /dev/null +++ b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRule2.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.core.animation; + +import android.os.Looper; +import android.os.SystemClock; +import android.util.AndroidRuntimeException; + +import androidx.annotation.NonNull; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.util.ArrayList; +import java.util.List; + +/** + * NOTE: this is a copy of the {@link androidx.core.animation.AnimatorTestRule} which attempts to + * circumvent the problems with {@link androidx.core.animation.AnimationHandler} having a static + * list of callbacks. + * + * TODO(b/275602127): remove this and use the original rule once we have the updated androidx code. + */ +public final class AnimatorTestRule2 implements TestRule { + + class TestAnimationHandler extends AnimationHandler { + TestAnimationHandler() { + super(new TestProvider()); + } + + List<AnimationFrameCallback> animationCallbacks = new ArrayList<>(); + + @Override + void addAnimationFrameCallback(AnimationFrameCallback callback) { + animationCallbacks.add(callback); + callback.doAnimationFrame(getCurrentTime()); + } + + @Override + public void removeCallback(AnimationFrameCallback callback) { + int id = animationCallbacks.indexOf(callback); + if (id >= 0) { + animationCallbacks.set(id, null); + } + } + + void onAnimationFrame(long frameTime) { + for (int i = 0; i < animationCallbacks.size(); i++) { + final AnimationFrameCallback callback = animationCallbacks.get(i); + if (callback == null) { + continue; + } + callback.doAnimationFrame(frameTime); + } + } + + @Override + void autoCancelBasedOn(ObjectAnimator objectAnimator) { + for (int i = animationCallbacks.size() - 1; i >= 0; i--) { + AnimationFrameCallback cb = animationCallbacks.get(i); + if (cb == null) { + continue; + } + if (objectAnimator.shouldAutoCancel(cb)) { + ((Animator) animationCallbacks.get(i)).cancel(); + } + } + } + } + + final TestAnimationHandler mTestHandler; + final long mStartTime; + private long mTotalTimeDelta = 0; + private final Object mLock = new Object(); + + public AnimatorTestRule2() { + mStartTime = SystemClock.uptimeMillis(); + mTestHandler = new TestAnimationHandler(); + } + + @NonNull + @Override + public Statement apply(@NonNull final Statement base, @NonNull Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + AnimationHandler.setTestHandler(mTestHandler); + try { + base.evaluate(); + } finally { + AnimationHandler.setTestHandler(null); + } + } + }; + } + + /** + * Advances the animation clock by the given amount of delta in milliseconds. This call will + * produce an animation frame to all the ongoing animations. This method needs to be + * called on the same thread as {@link Animator#start()}. + * + * @param timeDelta the amount of milliseconds to advance + */ + public void advanceTimeBy(long timeDelta) { + if (Looper.myLooper() == null) { + // Throw an exception + throw new AndroidRuntimeException("AnimationTestRule#advanceTimeBy(long) may only be" + + "called on Looper threads"); + } + synchronized (mLock) { + // Advance time & pulse a frame + mTotalTimeDelta += timeDelta < 0 ? 0 : timeDelta; + } + // produce a frame + mTestHandler.onAnimationFrame(getCurrentTime()); + } + + + /** + * Returns the current time in milliseconds tracked by AnimationHandler. Note that this is a + * different time than the time tracked by {@link SystemClock} This method needs to be called on + * the same thread as {@link Animator#start()}. + */ + public long getCurrentTime() { + if (Looper.myLooper() == null) { + // Throw an exception + throw new AndroidRuntimeException("AnimationTestRule#getCurrentTime() may only be" + + "called on Looper threads"); + } + synchronized (mLock) { + return mStartTime + mTotalTimeDelta; + } + } + + + private class TestProvider implements AnimationHandler.AnimationFrameCallbackProvider { + TestProvider() { + } + + @Override + public void onNewCallbackAdded(AnimationHandler.AnimationFrameCallback callback) { + callback.doAnimationFrame(getCurrentTime()); + } + + @Override + public void postFrameCallback() { + } + + @Override + public void setFrameDelay(long delay) { + } + + @Override + public long getFrameDelay() { + return 0; + } + } +} + diff --git a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleTest.kt b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleTest.kt new file mode 100644 index 000000000000..bddd60b5970a --- /dev/null +++ b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleTest.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package androidx.core.animation + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.doOnEnd +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +@RunWithLooper(setAsMainLooper = true) +class AnimatorTestRuleTest : SysuiTestCase() { + + @get:Rule val animatorTestRule = AnimatorTestRule2() + + @Test + fun testA() { + didTouchA = false + didTouchB = false + ObjectAnimator.ofFloat(0f, 1f).apply { + duration = 100 + doOnEnd { didTouchA = true } + start() + } + ObjectAnimator.ofFloat(0f, 1f).apply { + duration = 150 + doOnEnd { didTouchA = true } + start() + } + animatorTestRule.advanceTimeBy(100) + assertThat(didTouchA).isTrue() + assertThat(didTouchB).isFalse() + } + + @Test + fun testB() { + didTouchA = false + didTouchB = false + ObjectAnimator.ofFloat(0f, 1f).apply { + duration = 100 + doOnEnd { didTouchB = true } + start() + } + ObjectAnimator.ofFloat(0f, 1f).apply { + duration = 150 + doOnEnd { didTouchB = true } + start() + } + animatorTestRule.advanceTimeBy(100) + assertThat(didTouchA).isFalse() + assertThat(didTouchB).isTrue() + } + + companion object { + var didTouchA = false + var didTouchB = false + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index 50645e5daa09..7ce2b1cf38ee 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -17,6 +17,7 @@ package com.android.keyguard; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -151,10 +152,19 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { false); } - @Test public void testReset() { mKeyguardAbsKeyInputViewController.reset(); verify(mKeyguardMessageAreaController).setMessage("", false); + verify(mAbsKeyInputView).resetPasswordText(false, false); + verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt()); + } + + @Test + public void onResume_Reset() { + mKeyguardAbsKeyInputViewController.onResume(KeyguardSecurityView.VIEW_REVEALED); + verify(mKeyguardMessageAreaController).setMessage("", false); + verify(mAbsKeyInputView).resetPasswordText(false, false); + verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt()); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt index 13b3b1afd30b..082c8ccd9657 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt @@ -18,10 +18,8 @@ package com.android.keyguard import android.testing.AndroidTestingRunner import android.testing.TestableLooper -import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.EditText -import android.widget.ImageView import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.internal.widget.LockPatternUtils @@ -32,7 +30,6 @@ import com.android.systemui.util.concurrency.DelayableExecutor import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock @@ -40,7 +37,6 @@ import org.mockito.Mockito import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` -import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations @SmallTest @@ -80,9 +76,7 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { Mockito.`when`(keyguardPasswordView.findViewById<EditText>(R.id.passwordEntry)) .thenReturn(passwordEntry) `when`(keyguardPasswordView.resources).thenReturn(context.resources) - `when`(keyguardPasswordView.findViewById<ImageView>(R.id.switch_ime_button)) - .thenReturn(mock(ImageView::class.java)) - keyguardPasswordViewController = + keyguardPasswordViewController = KeyguardPasswordViewController( keyguardPasswordView, keyguardUpdateMonitor, @@ -119,18 +113,6 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { } @Test - fun onApplyWindowInsetsListener_onApplyWindowInsets() { - `when`(keyguardViewController.isBouncerShowing).thenReturn(false) - val argumentCaptor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java) - - keyguardPasswordViewController.onViewAttached() - verify(keyguardPasswordView).setOnApplyWindowInsetsListener(argumentCaptor.capture()) - argumentCaptor.value.onApplyWindowInsets(keyguardPasswordView, null) - - verify(keyguardPasswordView).hideKeyboard() - } - - @Test fun testHideKeyboardWhenOnPause() { keyguardPasswordViewController.onPause() keyguardPasswordView.post { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index 85dbdb8330a3..6ae28b73b348 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -31,6 +31,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito.never @@ -119,4 +120,24 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { mKeyguardPatternViewController.startAppearAnimation() verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean()) } + + @Test + fun reset() { + mKeyguardPatternViewController.reset() + verify(mLockPatternView).setInStealthMode(anyBoolean()) + verify(mLockPatternView).enableInput() + verify(mLockPatternView).setEnabled(true) + verify(mLockPatternView).clearPattern() + verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt()) + } + + @Test + fun resume() { + mKeyguardPatternViewController.onResume(KeyguardSecurityView.VIEW_REVEALED) + verify(mLockPatternView).setInStealthMode(anyBoolean()) + verify(mLockPatternView).enableInput() + verify(mLockPatternView).setEnabled(true) + verify(mLockPatternView).clearPattern() + verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt()) + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt index a1af8e8fac9c..70476aa088dc 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt @@ -129,10 +129,11 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { } @Test - fun startAppearAnimation_withAutoPinConfirmation() { + fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsLessThan5() { `when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true) `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6) `when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true) + `when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(3) `when`(passwordTextView.text).thenReturn("") pinViewController.startAppearAnimation() @@ -141,4 +142,19 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { verify(passwordTextView).setUsePinShapes(true) verify(passwordTextView).setIsPinHinting(true) } + + @Test + fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsMoreThan5() { + `when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true) + `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6) + `when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true) + `when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(6) + `when`(passwordTextView.text).thenReturn("") + + pinViewController.startAppearAnimation() + verify(deleteButton).visibility = View.INVISIBLE + verify(enterButton).visibility = View.VISIBLE + verify(passwordTextView).setUsePinShapes(true) + verify(passwordTextView).setIsPinHinting(true) + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index b73330fb09c8..65f8610cfd43 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -393,6 +393,45 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { } @Test + public void showNextSecurityScreenOrFinish_DeviceNotSecure() { + // GIVEN the current security method is SimPin + when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false); + mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin); + + // WHEN a request is made from the SimPin screens to show the next security method + when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.None); + mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish( + /* authenticated= */true, + TARGET_USER_ID, + /* bypassSecondaryLockScreen= */true, + SecurityMode.SimPin); + + // THEN the next security method of None will dismiss keyguard. + verify(mViewMediatorCallback).keyguardDone(anyBoolean(), anyInt()); + } + + @Test + public void showNextSecurityScreenOrFinish_DeviceNotSecure_prevent_bypass_on() { + when(mFeatureFlags.isEnabled(Flags.PREVENT_BYPASS_KEYGUARD)).thenReturn(true); + // GIVEN the current security method is SimPin + when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false); + mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin); + + // WHEN a request is made from the SimPin screens to show the next security method + when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.None); + mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish( + /* authenticated= */true, + TARGET_USER_ID, + /* bypassSecondaryLockScreen= */true, + SecurityMode.SimPin); + + // THEN the next security method of None will dismiss keyguard. + verify(mViewMediatorCallback).keyguardDone(anyBoolean(), anyInt()); + } + + @Test public void showNextSecurityScreenOrFinish_ignoresCallWhenSecurityMethodHasChanged() { //GIVEN current security mode has been set to PIN mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.PIN); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index afb54d2df49f..eaf7b1ec2100 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -35,6 +35,7 @@ import androidx.asynclayoutinflater.view.AsyncLayoutInflater; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.flags.FeatureFlags; @@ -42,6 +43,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -76,6 +78,8 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { private KeyguardSecurityCallback mKeyguardSecurityCallback; @Mock private FeatureFlags mFeatureFlags; + @Mock + private ViewMediatorCallback mViewMediatorCallback; private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController; @@ -92,7 +96,7 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView, mLayoutInflater, mAsyncLayoutInflater, mKeyguardSecurityViewControllerFactory, - mEmergencyButtonControllerFactory, mFeatureFlags); + mEmergencyButtonControllerFactory, mFeatureFlags, mViewMediatorCallback); } @Test @@ -123,6 +127,19 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { } @Test + public void asynchronouslyInflateView_setNeedsInput() { + ArgumentCaptor<AsyncLayoutInflater.OnInflateFinishedListener> argumentCaptor = + ArgumentCaptor.forClass(AsyncLayoutInflater.OnInflateFinishedListener.class); + mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN, + mKeyguardSecurityCallback, null); + verify(mAsyncLayoutInflater).inflate(anyInt(), eq(mView), argumentCaptor.capture()); + argumentCaptor.getValue().onInflateFinished( + LayoutInflater.from(getContext()).inflate(R.layout.keyguard_password_view, null), + R.layout.keyguard_password_view, mView); + verify(mViewMediatorCallback).setNeedsInput(anyBoolean()); + } + + @Test public void onDensityOrFontScaleChanged() { mKeyguardSecurityViewFlipperController.clearViews(); verify(mView).removeAllViews(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index a8b42544fd87..08813a7fb48a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -84,9 +84,11 @@ import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorProperties; import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; @@ -194,8 +196,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Mock private FaceManager mFaceManager; @Mock - private List<FaceSensorPropertiesInternal> mFaceSensorProperties; - @Mock private BiometricManager mBiometricManager; @Mock private PackageManager mPackageManager; @@ -254,6 +254,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Mock private Uri mURI; + private List<FaceSensorPropertiesInternal> mFaceSensorProperties; private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; private final int mCurrentUserId = 100; private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0); @@ -274,21 +275,22 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private StatusBarStateController.StateListener mStatusBarStateListener; private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback; private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig; + private IFingerprintAuthenticatorsRegisteredCallback + mFingerprintAuthenticatorsRegisteredCallback; + private IFaceAuthenticatorsRegisteredCallback mFaceAuthenticatorsRegisteredCallback; private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999); @Before public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); + + mFaceSensorProperties = + List.of(createFaceSensorProperties(/* supportsFaceDetection = */ false)); when(mFaceManager.isHardwareDetected()).thenReturn(true); when(mAuthController.isFaceAuthEnrolled(anyInt())).thenReturn(true); when(mFaceManager.getSensorPropertiesInternal()).thenReturn(mFaceSensorProperties); when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId); - // IBiometricsFace@1.0 does not support detection, only authentication. - when(mFaceSensorProperties.isEmpty()).thenReturn(false); - when(mFaceSensorProperties.get(anyInt())).thenReturn( - createFaceSensorProperties(/* supportsFaceDetection = */ false)); - mFingerprintSensorProperties = List.of( new FingerprintSensorPropertiesInternal(1 /* sensorId */, FingerprintSensorProperties.STRENGTH_STRONG, @@ -345,6 +347,20 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext); + ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> faceCaptor = + ArgumentCaptor.forClass(IFaceAuthenticatorsRegisteredCallback.class); + verify(mFaceManager).addAuthenticatorsRegisteredCallback(faceCaptor.capture()); + mFaceAuthenticatorsRegisteredCallback = faceCaptor.getValue(); + mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties); + + ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> fingerprintCaptor = + ArgumentCaptor.forClass(IFingerprintAuthenticatorsRegisteredCallback.class); + verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( + fingerprintCaptor.capture()); + mFingerprintAuthenticatorsRegisteredCallback = fingerprintCaptor.getValue(); + mFingerprintAuthenticatorsRegisteredCallback + .onAllAuthenticatorsRegistered(mFingerprintSensorProperties); + verify(mBiometricManager) .registerEnabledOnKeyguardCallback(mBiometricEnabledCallbackArgCaptor.capture()); mBiometricEnabledOnKeyguardCallback = mBiometricEnabledCallbackArgCaptor.getValue(); @@ -651,7 +667,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void whenDetectFace_biometricDetectCallback() { + public void whenDetectFace_biometricDetectCallback() throws RemoteException { ArgumentCaptor<FaceManager.FaceDetectionCallback> faceDetectCallbackCaptor = ArgumentCaptor.forClass(FaceManager.FaceDetectionCallback.class); @@ -801,7 +817,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void nofaceDetect_whenStrongAuthRequiredAndBypassUdfpsSupportedAndFpRunning() { + public void nofaceDetect_whenStrongAuthRequiredAndBypassUdfpsSupportedAndFpRunning() + throws RemoteException { // GIVEN bypass is enabled, face detection is supported lockscreenBypassIsAllowed(); supportsFaceDetection(); @@ -825,7 +842,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void faceDetect_whenStrongAuthRequiredAndBypass() { + public void faceDetect_whenStrongAuthRequiredAndBypass() throws RemoteException { givenDetectFace(); // FACE detect is triggered, not authenticate @@ -1360,9 +1377,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void startsListeningForSfps_whenKeyguardIsVisible_ifRequireInteractiveToAuthEnabled() throws RemoteException { // SFPS supported and enrolled - final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); - props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON)); - when(mAuthController.getSfpsProps()).thenReturn(props); + when(mAuthController.isSfpsSupported()).thenReturn(true); when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); // WHEN require interactive to auth is disabled, and keyguard is not awake @@ -1401,9 +1416,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void notListeningForSfps_whenGoingToSleep_ifRequireInteractiveToAuthEnabled() throws RemoteException { // GIVEN SFPS supported and enrolled - final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); - props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON)); - when(mAuthController.getSfpsProps()).thenReturn(props); + when(mAuthController.isSfpsSupported()).thenReturn(true); when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); // GIVEN Preconditions for sfps auth to run @@ -2618,6 +2631,37 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(captor.getValue().getWakeReason()) .isEqualTo(PowerManager.WAKE_REASON_POWER_BUTTON); } + @Test + public void testFingerprintSensorProperties() throws RemoteException { + mFingerprintAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered( + new ArrayList<>()); + + assertThat(mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible( + KeyguardUpdateMonitor.getCurrentUser())).isFalse(); + + mFingerprintAuthenticatorsRegisteredCallback + .onAllAuthenticatorsRegistered(mFingerprintSensorProperties); + + verifyFingerprintAuthenticateCall(); + assertThat(mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible( + KeyguardUpdateMonitor.getCurrentUser())).isTrue(); + } + @Test + public void testFaceSensorProperties() throws RemoteException { + mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(new ArrayList<>()); + + assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser( + KeyguardUpdateMonitor.getCurrentUser())).isFalse(); + + mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties); + biometricsEnabledForCurrentUser(); + + verifyFaceAuthenticateNeverCalled(); + verifyFaceDetectNeverCalled(); + assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser( + KeyguardUpdateMonitor.getCurrentUser())).isTrue(); + } + private void verifyFingerprintAuthenticateNeverCalled() { verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any()); @@ -2660,10 +2704,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); } - private void supportsFaceDetection() { - when(mFaceSensorProperties.get(anyInt())) - .thenReturn(createFaceSensorProperties( - /* supportsFaceDetection = */ true)); + private void supportsFaceDetection() throws RemoteException { + mFaceSensorProperties = + List.of(createFaceSensorProperties(/* supportsFaceDetection = */ true)); + mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties); } private void lockscreenBypassIsAllowed() { @@ -2843,8 +2887,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } private void givenUdfpsSupported() { - Assert.assertFalse(mFingerprintSensorProperties.isEmpty()); - when(mAuthController.getUdfpsProps()).thenReturn(mFingerprintSensorProperties); + when(mAuthController.isUdfpsSupported()).thenReturn(true); Assert.assertTrue(mKeyguardUpdateMonitor.isUdfpsSupported()); } @@ -2873,7 +2916,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); } - private void givenDetectFace() { + private void givenDetectFace() throws RemoteException { // GIVEN bypass is enabled, face detection is supported and strong auth is required lockscreenBypassIsAllowed(); supportsFaceDetection(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt index eb8295653199..353a7c370ab6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt @@ -26,6 +26,8 @@ import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SystemSettings @@ -34,6 +36,10 @@ import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations private const val ON: Int = 1 @@ -53,6 +59,9 @@ class FontScalingDialogTest : SysuiTestCase() { .getResources() .getStringArray(com.android.settingslib.R.array.entryvalues_font_size) + @Captor + private lateinit var seekBarChangeCaptor: ArgumentCaptor<SeekBar.OnSeekBarChangeListener> + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -61,7 +70,7 @@ class FontScalingDialogTest : SysuiTestCase() { secureSettings = FakeSettings() backgroundExecutor = FakeExecutor(FakeSystemClock()) fontScalingDialog = - FontScalingDialog(mContext, systemSettings, secureSettings, backgroundExecutor) + spy(FontScalingDialog(mContext, systemSettings, secureSettings, backgroundExecutor)) } @Test @@ -70,7 +79,7 @@ class FontScalingDialogTest : SysuiTestCase() { val seekBar: SeekBar = fontScalingDialog.findViewById<SeekBar>(R.id.seekbar)!! val progress: Int = seekBar.getProgress() - val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f) + val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f) assertThat(currentScale).isEqualTo(fontSizeValueArray[progress].toFloat()) @@ -91,7 +100,7 @@ class FontScalingDialogTest : SysuiTestCase() { iconEndFrame.performClick() backgroundExecutor.runAllReady() - val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f) + val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f) assertThat(seekBar.getProgress()).isEqualTo(1) assertThat(currentScale).isEqualTo(fontSizeValueArray[1].toFloat()) @@ -112,7 +121,7 @@ class FontScalingDialogTest : SysuiTestCase() { iconStartFrame.performClick() backgroundExecutor.runAllReady() - val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f) + val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f) assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2) assertThat(currentScale) .isEqualTo(fontSizeValueArray[fontSizeValueArray.size - 2].toFloat()) @@ -141,4 +150,64 @@ class FontScalingDialogTest : SysuiTestCase() { fontScalingDialog.dismiss() } + + @Test + fun dragSeekbar_systemFontSizeSettingsDoesNotChange() { + val slider: SeekBarWithIconButtonsView = spy(SeekBarWithIconButtonsView(mContext)) + whenever( + fontScalingDialog.findViewById<SeekBarWithIconButtonsView>(R.id.font_scaling_slider) + ) + .thenReturn(slider) + fontScalingDialog.show() + verify(slider).setOnSeekBarChangeListener(capture(seekBarChangeCaptor)) + val seekBar: SeekBar = slider.findViewById(R.id.seekbar)!! + + // Default seekbar progress for font size is 1, simulate dragging to 0 without + // releasing the finger. + seekBarChangeCaptor.value.onStartTrackingTouch(seekBar) + // Update seekbar progress. This will trigger onProgressChanged in the + // OnSeekBarChangeListener and the seekbar could get updated progress value + // in onStopTrackingTouch. + seekBar.progress = 0 + backgroundExecutor.runAllReady() + + // Verify that the scale of font size remains the default value 1.0f. + var systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f) + assertThat(systemScale).isEqualTo(1.0f) + + // Simulate releasing the finger from the seekbar. + seekBarChangeCaptor.value.onStopTrackingTouch(seekBar) + backgroundExecutor.runAllReady() + + // Verify that the scale of font size has been updated. + systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f) + assertThat(systemScale).isEqualTo(fontSizeValueArray[0].toFloat()) + + fontScalingDialog.dismiss() + } + + @Test + fun dragSeekBar_createTextPreview() { + val slider: SeekBarWithIconButtonsView = spy(SeekBarWithIconButtonsView(mContext)) + whenever( + fontScalingDialog.findViewById<SeekBarWithIconButtonsView>(R.id.font_scaling_slider) + ) + .thenReturn(slider) + fontScalingDialog.show() + verify(slider).setOnSeekBarChangeListener(capture(seekBarChangeCaptor)) + val seekBar: SeekBar = slider.findViewById(R.id.seekbar)!! + + // Default seekbar progress for font size is 1, simulate dragging to 0 without + // releasing the finger + seekBarChangeCaptor.value.onStartTrackingTouch(seekBar) + seekBarChangeCaptor.value.onProgressChanged( + seekBar, + /* progress= */ 0, + /* fromUser= */ false + ) + backgroundExecutor.runAllReady() + + verify(fontScalingDialog).createTextPreview(/* index= */ 0) + fontScalingDialog.dismiss() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt index 0ab675cd6873..33345b5b9f75 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt @@ -51,13 +51,10 @@ import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG import android.view.WindowMetrics import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView -import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestableContext import com.android.systemui.dump.DumpManager -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags.MODERN_ALTERNATE_BOUNCER import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository @@ -113,7 +110,6 @@ class SideFpsControllerTest : SysuiTestCase() { private lateinit var keyguardBouncerRepository: FakeKeyguardBouncerRepository private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor - private val featureFlags = FakeFeatureFlags() private val executor = FakeExecutor(FakeSystemClock()) private lateinit var overlayController: ISidefpsController private lateinit var sideFpsController: SideFpsController @@ -134,7 +130,6 @@ class SideFpsControllerTest : SysuiTestCase() { @Before fun setup() { - featureFlags.set(MODERN_ALTERNATE_BOUNCER, true) keyguardBouncerRepository = FakeKeyguardBouncerRepository() alternateBouncerInteractor = AlternateBouncerInteractor( @@ -144,8 +139,6 @@ class SideFpsControllerTest : SysuiTestCase() { FakeBiometricSettingsRepository(), FakeDeviceEntryFingerprintAuthRepository(), FakeSystemClock(), - mock(KeyguardUpdateMonitor::class.java), - featureFlags, ) context.addMockSystemService(DisplayManager::class.java, displayManager) @@ -246,7 +239,6 @@ class SideFpsControllerTest : SysuiTestCase() { handler, alternateBouncerInteractor, TestCoroutineScope(), - featureFlags, dumpManager, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java index dbbc2663a879..a878aec4c753 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java @@ -147,7 +147,6 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase { protected UdfpsKeyguardViewController createUdfpsKeyguardViewController( boolean useModernBouncer, boolean useExpandedOverlay) { - mFeatureFlags.set(Flags.MODERN_ALTERNATE_BOUNCER, useModernBouncer); mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, useExpandedOverlay); UdfpsKeyguardViewController controller = new UdfpsKeyguardViewController( mView, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt index cefa9b129262..b848413423d1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt @@ -21,9 +21,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityModel -import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.classifier.FalsingCollector -import com.android.systemui.flags.FeatureFlags import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.BouncerView import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository @@ -100,8 +98,6 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle mock(BiometricSettingsRepository::class.java), mock(DeviceEntryFingerprintAuthRepository::class.java), mock(SystemClock::class.java), - mock(KeyguardUpdateMonitor::class.java), - mock(FeatureFlags::class.java) ) return createUdfpsKeyguardViewController( /* useModernBouncer */ true, /* useExpandedOverlay */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt index 16fb50c15af6..38372a33f1e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt @@ -29,7 +29,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.wm.shell.TaskViewFactory +import com.android.wm.shell.taskview.TaskViewFactory import org.junit.Before import org.junit.Test import org.junit.runner.RunWith diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt index 845848071f54..605dc3f2e90a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt @@ -59,8 +59,8 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock -import com.android.wm.shell.TaskView -import com.android.wm.shell.TaskViewFactory +import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewFactory import com.google.common.truth.Truth.assertThat import java.util.Optional import java.util.function.Consumer diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt index 6a6a65a601fb..c3506e80966b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt @@ -24,7 +24,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.policy.KeyguardStateController -import com.android.wm.shell.TaskView +import com.android.wm.shell.taskview.TaskView import org.junit.Before import org.junit.Test import org.junit.runner.RunWith diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt index 9df7992f979f..f7c8ccaf731a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt @@ -36,7 +36,7 @@ import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock -import com.android.wm.shell.TaskView +import com.android.wm.shell.taskview.TaskView import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java index 2a72e7d85d3c..18abfa546ea6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java @@ -26,8 +26,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.res.Resources; +import android.graphics.Region; import android.os.Handler; import android.testing.AndroidTestingRunner; +import android.view.AttachedSurfaceControl; import android.view.ViewGroup; import android.view.ViewRootImpl; import android.view.ViewTreeObserver; @@ -76,6 +78,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { ComplicationHostViewController mComplicationHostViewController; @Mock + AttachedSurfaceControl mAttachedSurfaceControl; + + @Mock ViewGroup mDreamOverlayContentView; @Mock @@ -108,6 +113,8 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { when(mDreamOverlayContainerView.getResources()).thenReturn(mResources); when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver); when(mDreamOverlayContainerView.getViewRootImpl()).thenReturn(mViewRoot); + when(mDreamOverlayContainerView.getRootSurfaceControl()) + .thenReturn(mAttachedSurfaceControl); mController = new DreamOverlayContainerViewController( mDreamOverlayContainerView, @@ -128,6 +135,12 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { } @Test + public void testRootSurfaceControlInsetSetOnAttach() { + mController.onViewAttached(); + verify(mAttachedSurfaceControl).setTouchableRegion(eq(Region.obtain())); + } + + @Test public void testDreamOverlayStatusBarViewControllerInitialized() { mController.init(); verify(mDreamOverlayStatusBarViewController).init(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt index 5dc04f7efa63..fb7d379c0627 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt @@ -30,6 +30,8 @@ import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.AuthController @@ -42,7 +44,6 @@ import com.android.systemui.keyguard.data.repository.BiometricType.UNDER_DISPLAY import com.android.systemui.keyguard.shared.model.DevicePosture import com.android.systemui.statusbar.policy.DevicePostureController import com.android.systemui.user.data.repository.FakeUserRepository -import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat @@ -78,6 +79,8 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var biometricManager: BiometricManager + @Captor + private lateinit var strongAuthTracker: ArgumentCaptor<LockPatternUtils.StrongAuthTracker> @Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback> @Captor private lateinit var biometricManagerCallback: @@ -112,12 +115,12 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { devicePolicyManager = devicePolicyManager, scope = testScope.backgroundScope, backgroundDispatcher = testDispatcher, - looper = testableLooper!!.looper, - dumpManager = dumpManager, biometricManager = biometricManager, devicePostureRepository = devicePostureRepository, + dumpManager = dumpManager, ) testScope.runCurrent() + verify(lockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture()) } @Test @@ -147,21 +150,18 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { val strongBiometricAllowed = collectLastValue(underTest.isStrongBiometricAllowed) runCurrent() - val captor = argumentCaptor<LockPatternUtils.StrongAuthTracker>() - verify(lockPatternUtils).registerStrongAuthTracker(captor.capture()) - - captor.value.stub.onStrongAuthRequiredChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) - testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper + onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) assertThat(strongBiometricAllowed()).isTrue() - captor.value.stub.onStrongAuthRequiredChanged( - STRONG_AUTH_REQUIRED_AFTER_BOOT, - PRIMARY_USER_ID - ) - testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper + onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_BOOT, PRIMARY_USER_ID) assertThat(strongBiometricAllowed()).isFalse() } + private fun onStrongAuthChanged(flags: Int, userId: Int) { + strongAuthTracker.value.stub.onStrongAuthRequiredChanged(flags, userId) + testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper + } + @Test fun fingerprintDisabledByDpmChange() = testScope.runTest { @@ -351,6 +351,30 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { assertThat(isFaceAuthSupported()).isTrue() } + @Test + fun userInLockdownUsesStrongAuthFlagsToDetermineValue() = + testScope.runTest { + createBiometricSettingsRepository() + + val isUserInLockdown = collectLastValue(underTest.isCurrentUserInLockdown) + // has default value. + assertThat(isUserInLockdown()).isFalse() + + // change strong auth flags for another user. + // Combine with one more flag to check if we do the bitwise and + val inLockdown = + STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN or STRONG_AUTH_REQUIRED_AFTER_TIMEOUT + onStrongAuthChanged(inLockdown, ANOTHER_USER_ID) + + // Still false. + assertThat(isUserInLockdown()).isFalse() + + // change strong auth flags for current user. + onStrongAuthChanged(inLockdown, PRIMARY_USER_ID) + + assertThat(isUserInLockdown()).isTrue() + } + private fun enrollmentChange(biometricType: BiometricType, userId: Int, enabled: Boolean) { authControllerCallback.value.onEnrollmentsChanged(biometricType, userId, enabled) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt index 0519a44d55ba..70f766f719e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt @@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.AuthController import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dump.DumpManager import com.android.systemui.util.mockito.whenever @@ -37,6 +38,7 @@ import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -46,7 +48,9 @@ import org.mockito.MockitoAnnotations class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var dumpManager: DumpManager - @Captor private lateinit var callbackCaptor: ArgumentCaptor<KeyguardUpdateMonitorCallback> + @Mock private lateinit var authController: AuthController + @Captor + private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> private lateinit var testScope: TestScope @@ -59,6 +63,7 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { underTest = DeviceEntryFingerprintAuthRepositoryImpl( + authController, keyguardUpdateMonitor, testScope.backgroundScope, dumpManager, @@ -67,7 +72,7 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { @After fun tearDown() { - verify(keyguardUpdateMonitor).removeCallback(callbackCaptor.value) + // verify(keyguardUpdateMonitor).removeCallback(updateMonitorCallback.value) } @Test @@ -76,8 +81,8 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { val isLockedOutValue = collectLastValue(underTest.isLockedOut) runCurrent() - verify(keyguardUpdateMonitor).registerCallback(callbackCaptor.capture()) - val callback = callbackCaptor.value + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + val callback = updateMonitorCallback.value whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(true) callback.onLockedOutStateChanged(BiometricSourceType.FACE) @@ -90,4 +95,63 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { callback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT) assertThat(isLockedOutValue()).isFalse() } + + @Test + fun fpRunningStateIsPropagated() = + testScope.runTest { + val isRunning = collectLastValue(underTest.isRunning) + whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(true) + + // Initial value is available + assertThat(isRunning()).isTrue() + + verify(keyguardUpdateMonitor, atLeastOnce()) + .registerCallback(updateMonitorCallback.capture()) + invokeOnCallback { + it.onBiometricRunningStateChanged(false, BiometricSourceType.FINGERPRINT) + } + + assertThat(isRunning()).isFalse() + + invokeOnCallback { it.onBiometricRunningStateChanged(true, BiometricSourceType.FACE) } + + assertThat(isRunning()).isFalse() + + updateMonitorCallback.value.onBiometricRunningStateChanged( + true, + BiometricSourceType.FINGERPRINT + ) + assertThat(isRunning()).isTrue() + } + + private fun invokeOnCallback(action: (KeyguardUpdateMonitorCallback) -> Unit) { + updateMonitorCallback.allValues.forEach { action(it) } + } + + @Test + fun enabledFingerprintTypeProvidesTheCorrectOutput() = + testScope.runTest { + whenever(authController.isSfpsSupported).thenReturn(true) + whenever(authController.isUdfpsSupported).thenReturn(false) + whenever(authController.isRearFpsSupported).thenReturn(false) + + assertThat(underTest.availableFpSensorType).isEqualTo(BiometricType.SIDE_FINGERPRINT) + + whenever(authController.isSfpsSupported).thenReturn(false) + whenever(authController.isUdfpsSupported).thenReturn(true) + whenever(authController.isRearFpsSupported).thenReturn(false) + + assertThat(underTest.availableFpSensorType) + .isEqualTo(BiometricType.UNDER_DISPLAY_FINGERPRINT) + + whenever(authController.isSfpsSupported).thenReturn(false) + whenever(authController.isUdfpsSupported).thenReturn(false) + whenever(authController.isRearFpsSupported).thenReturn(true) + + assertThat(underTest.availableFpSensorType).isEqualTo(BiometricType.REAR_FINGERPRINT) + + whenever(authController.isRearFpsSupported).thenReturn(false) + + assertThat(underTest.availableFpSensorType).isNull() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt index 86246f7af033..e7e59697e8ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt @@ -18,11 +18,8 @@ package com.android.systemui.keyguard.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.ViewMediatorCallback import com.android.systemui.SysuiTestCase -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository @@ -40,10 +37,8 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.mock -import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @@ -58,9 +53,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var systemClock: SystemClock - @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var bouncerLogger: TableLogBuffer - private lateinit var featureFlags: FakeFeatureFlags @Before fun setup() { @@ -74,7 +67,6 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { ) biometricSettingsRepository = FakeBiometricSettingsRepository() deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository() - featureFlags = FakeFeatureFlags().apply { this.set(Flags.MODERN_ALTERNATE_BOUNCER, true) } underTest = AlternateBouncerInteractor( statusBarStateController, @@ -83,8 +75,6 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { biometricSettingsRepository, deviceEntryFingerprintAuthRepository, systemClock, - keyguardUpdateMonitor, - featureFlags, ) } @@ -135,14 +125,6 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { } @Test - fun canShowAlternateBouncerForFingerprint_isDozing() { - givenCanShowAlternateBouncer() - whenever(statusBarStateController.isDozing).thenReturn(true) - - assertFalse(underTest.canShowAlternateBouncerForFingerprint()) - } - - @Test fun show_whenCanShow() { givenCanShowAlternateBouncer() @@ -182,42 +164,6 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { assertFalse(bouncerRepository.alternateBouncerVisible.value) } - @Test - fun onUnlockedIsFalse_doesNotHide() { - // GIVEN alternate bouncer is showing - bouncerRepository.setAlternateVisible(true) - - val keyguardStateControllerCallbackCaptor = - ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java) - verify(keyguardStateController).addCallback(keyguardStateControllerCallbackCaptor.capture()) - - // WHEN isUnlocked=false - givenCanShowAlternateBouncer() - whenever(keyguardStateController.isUnlocked).thenReturn(false) - keyguardStateControllerCallbackCaptor.value.onUnlockedChanged() - - // THEN the alternate bouncer is still visible - assertTrue(bouncerRepository.alternateBouncerVisible.value) - } - - @Test - fun onUnlockedChangedIsTrue_hide() { - // GIVEN alternate bouncer is showing - bouncerRepository.setAlternateVisible(true) - - val keyguardStateControllerCallbackCaptor = - ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java) - verify(keyguardStateController).addCallback(keyguardStateControllerCallbackCaptor.capture()) - - // WHEN isUnlocked=true - givenCanShowAlternateBouncer() - whenever(keyguardStateController.isUnlocked).thenReturn(true) - keyguardStateControllerCallbackCaptor.value.onUnlockedChanged() - - // THEN the alternate bouncer is hidden - assertFalse(bouncerRepository.alternateBouncerVisible.value) - } - private fun givenCanShowAlternateBouncer() { bouncerRepository.setAlternateBouncerUIAvailable(true) biometricSettingsRepository.setFingerprintEnrolled(true) @@ -225,7 +171,6 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true) deviceEntryFingerprintAuthRepository.setLockedOut(false) whenever(keyguardStateController.isUnlocked).thenReturn(false) - whenever(statusBarStateController.isDozing).thenReturn(false) } private fun givenCannotShowAlternateBouncer() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt index bdc33f45c717..4c8a0a51bcdf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt @@ -131,6 +131,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { verify(repository).setPrimaryShowingSoon(false) verify(repository).setPrimaryShow(false) verify(mPrimaryBouncerCallbackInteractor).dispatchVisibilityChanged(View.INVISIBLE) + verify(repository).setPrimaryStartDisappearAnimation(null) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt index 91a6de6ae4c0..ea11f01ed580 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.lifecycle -import android.testing.TestableLooper.RunWithLooper import android.view.View import android.view.ViewTreeObserver import androidx.lifecycle.Lifecycle @@ -28,8 +27,16 @@ import com.android.systemui.util.Assert import com.android.systemui.util.mockito.argumentCaptor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.DisposableHandle -import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test @@ -41,9 +48,9 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) -@RunWithLooper class RepeatWhenAttachedTest : SysuiTestCase() { @JvmField @Rule val mockito = MockitoJUnit.rule() @@ -54,9 +61,13 @@ class RepeatWhenAttachedTest : SysuiTestCase() { private lateinit var block: Block private lateinit var attachListeners: MutableList<View.OnAttachStateChangeListener> + private lateinit var testScope: TestScope @Before fun setUp() { + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) + Dispatchers.setMain(testDispatcher) Assert.setTestThread(Thread.currentThread()) whenever(view.viewTreeObserver).thenReturn(viewTreeObserver) whenever(view.windowVisibility).thenReturn(View.GONE) @@ -71,186 +82,218 @@ class RepeatWhenAttachedTest : SysuiTestCase() { block = Block() } - @Test(expected = IllegalStateException::class) - fun `repeatWhenAttached - enforces main thread`() = runBlockingTest { - Assert.setTestThread(null) - - repeatWhenAttached() + @After + fun tearDown() { + Dispatchers.resetMain() } @Test(expected = IllegalStateException::class) - fun `repeatWhenAttached - dispose enforces main thread`() = runBlockingTest { - val disposableHandle = repeatWhenAttached() - Assert.setTestThread(null) + fun `repeatWhenAttached - enforces main thread`() = + testScope.runTest { + Assert.setTestThread(null) - disposableHandle.dispose() - } - - @Test - fun `repeatWhenAttached - view starts detached - runs block when attached`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(false) - repeatWhenAttached() - assertThat(block.invocationCount).isEqualTo(0) + repeatWhenAttached() + } - whenever(view.isAttachedToWindow).thenReturn(true) - attachListeners.last().onViewAttachedToWindow(view) + @Test(expected = IllegalStateException::class) + fun `repeatWhenAttached - dispose enforces main thread`() = + testScope.runTest { + val disposableHandle = repeatWhenAttached() + Assert.setTestThread(null) - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) - } + disposableHandle.dispose() + } @Test - fun `repeatWhenAttached - view already attached - immediately runs block`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - - repeatWhenAttached() - - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) - } + fun `repeatWhenAttached - view starts detached - runs block when attached`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(false) + repeatWhenAttached() + assertThat(block.invocationCount).isEqualTo(0) + + whenever(view.isAttachedToWindow).thenReturn(true) + attachListeners.last().onViewAttachedToWindow(view) + + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) + } @Test - fun `repeatWhenAttached - starts visible without focus - STARTED`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - whenever(view.windowVisibility).thenReturn(View.VISIBLE) + fun `repeatWhenAttached - view already attached - immediately runs block`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) - repeatWhenAttached() + repeatWhenAttached() - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED) - } + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) + } @Test - fun `repeatWhenAttached - starts with focus but invisible - CREATED`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - whenever(view.hasWindowFocus()).thenReturn(true) + fun `repeatWhenAttached - starts visible without focus - STARTED`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + whenever(view.windowVisibility).thenReturn(View.VISIBLE) - repeatWhenAttached() + repeatWhenAttached() - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) - } + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED) + } @Test - fun `repeatWhenAttached - starts visible and with focus - RESUMED`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - whenever(view.windowVisibility).thenReturn(View.VISIBLE) - whenever(view.hasWindowFocus()).thenReturn(true) + fun `repeatWhenAttached - starts with focus but invisible - CREATED`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + whenever(view.hasWindowFocus()).thenReturn(true) - repeatWhenAttached() + repeatWhenAttached() - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED) - } + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) + } @Test - fun `repeatWhenAttached - becomes visible without focus - STARTED`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - repeatWhenAttached() - val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>() - verify(viewTreeObserver).addOnWindowVisibilityChangeListener(listenerCaptor.capture()) + fun `repeatWhenAttached - starts visible and with focus - RESUMED`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + whenever(view.windowVisibility).thenReturn(View.VISIBLE) + whenever(view.hasWindowFocus()).thenReturn(true) - whenever(view.windowVisibility).thenReturn(View.VISIBLE) - listenerCaptor.value.onWindowVisibilityChanged(View.VISIBLE) + repeatWhenAttached() - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED) - } + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED) + } @Test - fun `repeatWhenAttached - gains focus but invisible - CREATED`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - repeatWhenAttached() - val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>() - verify(viewTreeObserver).addOnWindowFocusChangeListener(listenerCaptor.capture()) - - whenever(view.hasWindowFocus()).thenReturn(true) - listenerCaptor.value.onWindowFocusChanged(true) + fun `repeatWhenAttached - becomes visible without focus - STARTED`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + repeatWhenAttached() + val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>() + verify(viewTreeObserver).addOnWindowVisibilityChangeListener(listenerCaptor.capture()) + + whenever(view.windowVisibility).thenReturn(View.VISIBLE) + listenerCaptor.value.onWindowVisibilityChanged(View.VISIBLE) + + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED) + } - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) - } + @Test + fun `repeatWhenAttached - gains focus but invisible - CREATED`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + repeatWhenAttached() + val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>() + verify(viewTreeObserver).addOnWindowFocusChangeListener(listenerCaptor.capture()) + + whenever(view.hasWindowFocus()).thenReturn(true) + listenerCaptor.value.onWindowFocusChanged(true) + + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED) + } @Test - fun `repeatWhenAttached - becomes visible and gains focus - RESUMED`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - repeatWhenAttached() - val visibleCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>() - verify(viewTreeObserver).addOnWindowVisibilityChangeListener(visibleCaptor.capture()) - val focusCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>() - verify(viewTreeObserver).addOnWindowFocusChangeListener(focusCaptor.capture()) - - whenever(view.windowVisibility).thenReturn(View.VISIBLE) - visibleCaptor.value.onWindowVisibilityChanged(View.VISIBLE) - whenever(view.hasWindowFocus()).thenReturn(true) - focusCaptor.value.onWindowFocusChanged(true) - - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED) - } + fun `repeatWhenAttached - becomes visible and gains focus - RESUMED`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + repeatWhenAttached() + val visibleCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>() + verify(viewTreeObserver).addOnWindowVisibilityChangeListener(visibleCaptor.capture()) + val focusCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>() + verify(viewTreeObserver).addOnWindowFocusChangeListener(focusCaptor.capture()) + + whenever(view.windowVisibility).thenReturn(View.VISIBLE) + visibleCaptor.value.onWindowVisibilityChanged(View.VISIBLE) + whenever(view.hasWindowFocus()).thenReturn(true) + focusCaptor.value.onWindowFocusChanged(true) + + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED) + } @Test - fun `repeatWhenAttached - view gets detached - destroys the lifecycle`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - repeatWhenAttached() + fun `repeatWhenAttached - view gets detached - destroys the lifecycle`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + repeatWhenAttached() - whenever(view.isAttachedToWindow).thenReturn(false) - attachListeners.last().onViewDetachedFromWindow(view) + whenever(view.isAttachedToWindow).thenReturn(false) + attachListeners.last().onViewDetachedFromWindow(view) - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED) - } + runCurrent() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED) + } @Test - fun `repeatWhenAttached - view gets reattached - recreates a lifecycle`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - repeatWhenAttached() - whenever(view.isAttachedToWindow).thenReturn(false) - attachListeners.last().onViewDetachedFromWindow(view) - - whenever(view.isAttachedToWindow).thenReturn(true) - attachListeners.last().onViewAttachedToWindow(view) - - assertThat(block.invocationCount).isEqualTo(2) - assertThat(block.invocations[0].lifecycleState).isEqualTo(Lifecycle.State.DESTROYED) - assertThat(block.invocations[1].lifecycleState).isEqualTo(Lifecycle.State.CREATED) - } + fun `repeatWhenAttached - view gets reattached - recreates a lifecycle`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + repeatWhenAttached() + whenever(view.isAttachedToWindow).thenReturn(false) + attachListeners.last().onViewDetachedFromWindow(view) + + whenever(view.isAttachedToWindow).thenReturn(true) + attachListeners.last().onViewAttachedToWindow(view) + + runCurrent() + assertThat(block.invocationCount).isEqualTo(2) + assertThat(block.invocations[0].lifecycleState).isEqualTo(Lifecycle.State.DESTROYED) + assertThat(block.invocations[1].lifecycleState).isEqualTo(Lifecycle.State.CREATED) + } @Test - fun `repeatWhenAttached - dispose attached`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - val handle = repeatWhenAttached() + fun `repeatWhenAttached - dispose attached`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + val handle = repeatWhenAttached() - handle.dispose() + handle.dispose() - assertThat(attachListeners).isEmpty() - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED) - } + runCurrent() + assertThat(attachListeners).isEmpty() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED) + } @Test - fun `repeatWhenAttached - dispose never attached`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(false) - val handle = repeatWhenAttached() + fun `repeatWhenAttached - dispose never attached`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(false) + val handle = repeatWhenAttached() - handle.dispose() + handle.dispose() - assertThat(attachListeners).isEmpty() - assertThat(block.invocationCount).isEqualTo(0) - } + assertThat(attachListeners).isEmpty() + assertThat(block.invocationCount).isEqualTo(0) + } @Test - fun `repeatWhenAttached - dispose previously attached now detached`() = runBlockingTest { - whenever(view.isAttachedToWindow).thenReturn(true) - val handle = repeatWhenAttached() - attachListeners.last().onViewDetachedFromWindow(view) - - handle.dispose() - - assertThat(attachListeners).isEmpty() - assertThat(block.invocationCount).isEqualTo(1) - assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED) - } + fun `repeatWhenAttached - dispose previously attached now detached`() = + testScope.runTest { + whenever(view.isAttachedToWindow).thenReturn(true) + val handle = repeatWhenAttached() + attachListeners.last().onViewDetachedFromWindow(view) + + handle.dispose() + + runCurrent() + assertThat(attachListeners).isEmpty() + assertThat(block.invocationCount).isEqualTo(1) + assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED) + } private fun CoroutineScope.repeatWhenAttached(): DisposableHandle { return view.repeatWhenAttached( diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java new file mode 100644 index 000000000000..891a6f8a102c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media.dialog; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.KeyguardManager; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; +import android.media.AudioManager; +import android.media.session.MediaSessionManager; +import android.os.PowerExemptionManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.media.BluetoothMediaDevice; +import com.android.settingslib.media.LocalMediaManager; +import com.android.settingslib.media.MediaDevice; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; +import com.android.systemui.broadcast.BroadcastSender; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.media.nearby.NearbyMediaDevicesManager; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class MediaOutputBroadcastDialogTest extends SysuiTestCase { + + private static final String TEST_PACKAGE = "test_package"; + + // Mock + private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class); + private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class); + private final LocalBluetoothProfileManager mLocalBluetoothProfileManager = mock( + LocalBluetoothProfileManager.class); + private final LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast = mock( + LocalBluetoothLeBroadcast.class); + private final LocalBluetoothLeBroadcastAssistant mLocalBluetoothLeBroadcastAssistant = mock( + LocalBluetoothLeBroadcastAssistant.class); + private final BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata = mock( + BluetoothLeBroadcastMetadata.class); + private final BluetoothLeBroadcastReceiveState mBluetoothLeBroadcastReceiveState = mock( + BluetoothLeBroadcastReceiveState.class); + private final ActivityStarter mStarter = mock(ActivityStarter.class); + private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class); + private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class); + private final MediaDevice mBluetoothMediaDevice = mock(BluetoothMediaDevice.class); + private final BluetoothDevice mBluetoothDevice = mock(BluetoothDevice.class); + private final CachedBluetoothDevice mCachedBluetoothDevice = mock(CachedBluetoothDevice.class); + private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class); + private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); + private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock( + NearbyMediaDevicesManager.class); + private final AudioManager mAudioManager = mock(AudioManager.class); + private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class); + private KeyguardManager mKeyguardManager = mock(KeyguardManager.class); + private FeatureFlags mFlags = mock(FeatureFlags.class); + + private MediaOutputBroadcastDialog mMediaOutputBroadcastDialog; + private MediaOutputController mMediaOutputController; + + @Before + public void setUp() { + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(null); + + mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, + mMediaSessionManager, mLocalBluetoothManager, mStarter, + mNotifCollection, mDialogLaunchAnimator, + Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager, + mKeyguardManager, mFlags); + mMediaOutputController.mLocalMediaManager = mLocalMediaManager; + mMediaOutputBroadcastDialog = new MediaOutputBroadcastDialog(mContext, false, + mBroadcastSender, mMediaOutputController); + mMediaOutputBroadcastDialog.show(); + } + + @After + public void tearDown() { + mMediaOutputBroadcastDialog.dismissDialog(); + } + + @Test + public void connectBroadcastWithActiveDevice_noBroadcastMetadata_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(null); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean()); + } + + @Test + public void connectBroadcastWithActiveDevice_noConnectedMediaDevice_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn( + mBluetoothLeBroadcastMetadata); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(null); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean()); + } + + @Test + public void connectBroadcastWithActiveDevice_hasBroadcastSource_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn( + mBluetoothLeBroadcastMetadata); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mBluetoothMediaDevice); + when(((BluetoothMediaDevice) mBluetoothMediaDevice).getCachedDevice()) + .thenReturn(mCachedBluetoothDevice); + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); + List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>(); + sourceList.add(mBluetoothLeBroadcastReceiveState); + when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothDevice)).thenReturn( + sourceList); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean()); + } + + @Test + public void connectBroadcastWithActiveDevice_noBroadcastSource_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn( + mBluetoothLeBroadcastMetadata); + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mBluetoothMediaDevice); + when(mBluetoothMediaDevice.isBLEDevice()).thenReturn(true); + when(((BluetoothMediaDevice) mBluetoothMediaDevice).getCachedDevice()).thenReturn( + mCachedBluetoothDevice); + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); + List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>(); + when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothDevice)).thenReturn( + sourceList); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, times(1)).addSource(any(), any(), anyBoolean()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt index c6db565d7954..acde887818aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt @@ -24,7 +24,6 @@ import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep @@ -43,18 +42,12 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.mockito.Mock -import org.mockito.Mockito.never -import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) class MultiShadeMotionEventInteractorTest : SysuiTestCase() { - @Mock private lateinit var bouncerInteractor: PrimaryBouncerInteractor - private lateinit var underTest: MultiShadeMotionEventInteractor private lateinit var testScope: TestScope @@ -67,8 +60,6 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() { @Before fun setUp() { - MockitoAnnotations.initMocks(this) - testScope = TestScope() motionEvents = mutableSetOf() @@ -95,7 +86,6 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() { KeyguardTransitionInteractor( repository = keyguardTransitionRepository, ), - bouncerInteractor = bouncerInteractor, falsingManager = falsingManager, ) } @@ -400,7 +390,7 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() { } @Test - fun dragBouncerAboveTouchSlopAndUp_showsBouncer() = + fun dragUp_withUp_doesNotShowShade() = testScope.runTest { val leftShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.LEFT)) val rightShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.RIGHT)) @@ -423,24 +413,22 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() { x = 100f, // left shade y = yDragAmountPx, ) - assertThat(underTest.shouldIntercept(moveEvent)).isTrue() + assertThat(underTest.shouldIntercept(moveEvent)).isFalse() underTest.onTouchEvent(moveEvent, viewWidthPx = 1000) - verify(bouncerInteractor).show(isScrimmed = true) assertThat(leftShadeProxiedInput).isNull() assertThat(rightShadeProxiedInput).isNull() assertThat(singleShadeProxiedInput).isNull() val upEvent = motionEvent(MotionEvent.ACTION_UP) - assertThat(underTest.shouldIntercept(upEvent)).isTrue() + assertThat(underTest.shouldIntercept(upEvent)).isFalse() underTest.onTouchEvent(upEvent, viewWidthPx = 1000) - verify(bouncerInteractor, never()).hide() assertThat(leftShadeProxiedInput).isNull() assertThat(rightShadeProxiedInput).isNull() assertThat(singleShadeProxiedInput).isNull() } @Test - fun dragBouncerAboveTouchSlopAndCancel_falseTouch_showsThenHidesBouncer() = + fun dragUp_withCancel_falseTouch_showsThenHidesBouncer() = testScope.runTest { val leftShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.LEFT)) val rightShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.RIGHT)) @@ -463,18 +451,16 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() { x = 900f, // right shade y = yDragAmountPx, ) - assertThat(underTest.shouldIntercept(moveEvent)).isTrue() + assertThat(underTest.shouldIntercept(moveEvent)).isFalse() underTest.onTouchEvent(moveEvent, viewWidthPx = 1000) - verify(bouncerInteractor).show(isScrimmed = true) assertThat(leftShadeProxiedInput).isNull() assertThat(rightShadeProxiedInput).isNull() assertThat(singleShadeProxiedInput).isNull() falsingManager.setIsFalseTouch(true) val cancelEvent = motionEvent(MotionEvent.ACTION_CANCEL) - assertThat(underTest.shouldIntercept(cancelEvent)).isTrue() + assertThat(underTest.shouldIntercept(cancelEvent)).isFalse() underTest.onTouchEvent(cancelEvent, viewWidthPx = 1000) - verify(bouncerInteractor).hide() assertThat(leftShadeProxiedInput).isNull() assertThat(rightShadeProxiedInput).isNull() assertThat(singleShadeProxiedInput).isNull() diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt index 9897ce106137..fbe089a0616f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -25,6 +25,8 @@ import android.app.role.RoleManager.ROLE_NOTES import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.Intent.ACTION_MAIN +import android.content.Intent.CATEGORY_HOME import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT import android.content.Intent.FLAG_ACTIVITY_NEW_TASK @@ -278,7 +280,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { } @Test - fun showNoteTask_keyguardIsLocked_noteIsOpen_shouldStartActivityAndLogUiEvent() { + fun showNoteTask_keyguardIsLocked_noteIsOpen_shouldCloseActivityAndLogUiEvent() { val expectedInfo = NOTE_TASK_INFO.copy( entryPoint = NoteTaskEntryPoint.TAIL_BUTTON, @@ -291,8 +293,17 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!) - verify(context, never()).startActivityAsUser(any(), any()) - verifyZeroInteractions(bubbles, eventLogger) + val intentCaptor = argumentCaptor<Intent>() + val userCaptor = argumentCaptor<UserHandle>() + verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor)) + intentCaptor.value.let { intent -> + assertThat(intent.action).isEqualTo(ACTION_MAIN) + assertThat(intent.categories).contains(CATEGORY_HOME) + assertThat(intent.flags and FLAG_ACTIVITY_NEW_TASK).isEqualTo(FLAG_ACTIVITY_NEW_TASK) + } + assertThat(userCaptor.value).isEqualTo(userTracker.userHandle) + verify(eventLogger).logNoteTaskClosed(expectedInfo) + verifyZeroInteractions(bubbles) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 7e052bfa15d2..fb9336734d99 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -54,6 +54,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -95,6 +96,8 @@ public class TileServicesTest extends SysuiTestCase { private QSHost mQSHost; @Mock private PanelInteractor mPanelInteractor; + @Captor + private ArgumentCaptor<CommandQueue.Callbacks> mCallbacksArgumentCaptor; @Before public void setUp() throws Exception { @@ -251,6 +254,41 @@ public class TileServicesTest extends SysuiTestCase { verify(mPanelInteractor).forceCollapsePanels(); } + @Test + public void tileFreedForCorrectUser() throws RemoteException { + verify(mCommandQueue).addCallback(mCallbacksArgumentCaptor.capture()); + + ComponentName componentName = new ComponentName("pkg", "cls"); + CustomTile tileUser0 = mock(CustomTile.class); + CustomTile tileUser1 = mock(CustomTile.class); + + when(tileUser0.getComponent()).thenReturn(componentName); + when(tileUser1.getComponent()).thenReturn(componentName); + when(tileUser0.getUser()).thenReturn(0); + when(tileUser1.getUser()).thenReturn(1); + + // Create a tile for user 0 + TileServiceManager manager0 = mTileService.getTileWrapper(tileUser0); + when(manager0.isActiveTile()).thenReturn(true); + // Then create a tile for user 1 + TileServiceManager manager1 = mTileService.getTileWrapper(tileUser1); + when(manager1.isActiveTile()).thenReturn(true); + + // When the tile for user 0 gets freed + mTileService.freeService(tileUser0, manager0); + // and the user is 1 + when(mUserTracker.getUserId()).thenReturn(1); + + // a call to requestListeningState + mCallbacksArgumentCaptor.getValue().requestTileServiceListeningState(componentName); + mTestableLooper.processAllMessages(); + + // will call in the correct tile + verify(manager1).setBindRequested(true); + // and set it to listening + verify(manager1.getTileService()).onStartListening(); + } + private class TestTileServices extends TileServices { TestTileServices(QSHost host, Provider<Handler> handlerProvider, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, @@ -268,6 +306,8 @@ public class TileServicesTest extends SysuiTestCase { when(manager.isLifecycleStarted()).thenReturn(true); Binder b = new Binder(); when(manager.getToken()).thenReturn(b); + IQSTileService service = mock(IQSTileService.class); + when(manager.getTileService()).thenReturn(service); return manager; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt new file mode 100644 index 000000000000..c03849b35f54 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.data.repository + +import android.provider.Settings +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.qs.QSHost +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.util.settings.FakeSettings +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +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) +@OptIn(ExperimentalCoroutinesApi::class) +class TileSpecSettingsRepositoryTest : SysuiTestCase() { + + private lateinit var secureSettings: FakeSettings + + @Mock private lateinit var logger: QSPipelineLogger + + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) + + private lateinit var underTest: TileSpecSettingsRepository + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + secureSettings = FakeSettings() + + with(context.orCreateTestableResources) { + addOverride(R.string.quick_settings_tiles_default, DEFAULT_TILES) + } + + underTest = + TileSpecSettingsRepository( + secureSettings, + context.resources, + logger, + testDispatcher, + ) + } + + @Test + fun emptySetting_usesDefaultValue() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + assertThat(tiles).isEqualTo(getDefaultTileSpecs()) + } + + @Test + fun changeInSettings_changesValue() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + storeTilesForUser("a", 0) + assertThat(tiles).isEqualTo(listOf(TileSpec.create("a"))) + + storeTilesForUser("a,custom(b/c)", 0) + assertThat(tiles) + .isEqualTo(listOf(TileSpec.create("a"), TileSpec.create("custom(b/c)"))) + } + + @Test + fun tilesForCorrectUsers() = + testScope.runTest { + val tilesFromUser0 by collectLastValue(underTest.tilesSpecs(0)) + val tilesFromUser1 by collectLastValue(underTest.tilesSpecs(1)) + + val user0Tiles = "a" + val user1Tiles = "custom(b/c)" + storeTilesForUser(user0Tiles, 0) + storeTilesForUser(user1Tiles, 1) + + assertThat(tilesFromUser0).isEqualTo(user0Tiles.toTileSpecs()) + assertThat(tilesFromUser1).isEqualTo(user1Tiles.toTileSpecs()) + } + + @Test + fun invalidTilesAreNotPresent() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "d,custom(bad)" + storeTilesForUser(specs, 0) + + assertThat(tiles).isEqualTo(specs.toTileSpecs().filter { it != TileSpec.Invalid }) + } + + @Test + fun noValidTiles_defaultSet() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + storeTilesForUser("custom(bad),custom()", 0) + + assertThat(tiles).isEqualTo(getDefaultTileSpecs()) + } + + @Test + fun addTileAtEnd() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + storeTilesForUser("a", 0) + + underTest.addTile(userId = 0, TileSpec.create("b")) + + val expected = "a,b" + assertThat(loadTilesForUser(0)).isEqualTo(expected) + assertThat(tiles).isEqualTo(expected.toTileSpecs()) + } + + @Test + fun addTileAtPosition() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + storeTilesForUser("a,custom(b/c)", 0) + + underTest.addTile(userId = 0, TileSpec.create("d"), position = 1) + + val expected = "a,d,custom(b/c)" + assertThat(loadTilesForUser(0)).isEqualTo(expected) + assertThat(tiles).isEqualTo(expected.toTileSpecs()) + } + + @Test + fun addInvalidTile_noop() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "a,custom(b/c)" + storeTilesForUser(specs, 0) + + underTest.addTile(userId = 0, TileSpec.Invalid) + + assertThat(loadTilesForUser(0)).isEqualTo(specs) + assertThat(tiles).isEqualTo(specs.toTileSpecs()) + } + + @Test + fun addTileForOtherUser_addedInThatUser() = + testScope.runTest { + val tilesUser0 by collectLastValue(underTest.tilesSpecs(0)) + val tilesUser1 by collectLastValue(underTest.tilesSpecs(1)) + + storeTilesForUser("a", 0) + storeTilesForUser("b", 1) + + underTest.addTile(userId = 1, TileSpec.create("c")) + + assertThat(loadTilesForUser(0)).isEqualTo("a") + assertThat(tilesUser0).isEqualTo("a".toTileSpecs()) + assertThat(loadTilesForUser(1)).isEqualTo("b,c") + assertThat(tilesUser1).isEqualTo("b,c".toTileSpecs()) + } + + @Test + fun removeTile() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + storeTilesForUser("a,b", 0) + + underTest.removeTile(userId = 0, TileSpec.create("a")) + + assertThat(loadTilesForUser(0)).isEqualTo("b") + assertThat(tiles).isEqualTo("b".toTileSpecs()) + } + + @Test + fun removeTileNotThere_noop() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "a,b" + storeTilesForUser(specs, 0) + + underTest.removeTile(userId = 0, TileSpec.create("c")) + + assertThat(loadTilesForUser(0)).isEqualTo(specs) + assertThat(tiles).isEqualTo(specs.toTileSpecs()) + } + + @Test + fun removeInvalidTile_noop() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "a,b" + storeTilesForUser(specs, 0) + + underTest.removeTile(userId = 0, TileSpec.Invalid) + + assertThat(loadTilesForUser(0)).isEqualTo(specs) + assertThat(tiles).isEqualTo(specs.toTileSpecs()) + } + + @Test + fun removeTileFromSecondaryUser_removedOnlyInCorrectUser() = + testScope.runTest { + val user0Tiles by collectLastValue(underTest.tilesSpecs(0)) + val user1Tiles by collectLastValue(underTest.tilesSpecs(1)) + + val specs = "a,b" + storeTilesForUser(specs, 0) + storeTilesForUser(specs, 1) + + underTest.removeTile(userId = 1, TileSpec.create("a")) + + assertThat(loadTilesForUser(0)).isEqualTo(specs) + assertThat(user0Tiles).isEqualTo(specs.toTileSpecs()) + assertThat(loadTilesForUser(1)).isEqualTo("b") + assertThat(user1Tiles).isEqualTo("b".toTileSpecs()) + } + + @Test + fun changeTiles() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "a,custom(b/c)" + + underTest.setTiles(userId = 0, specs.toTileSpecs()) + + assertThat(loadTilesForUser(0)).isEqualTo(specs) + assertThat(tiles).isEqualTo(specs.toTileSpecs()) + } + + @Test + fun changeTiles_ignoresInvalid() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "a,custom(b/c)" + + underTest.setTiles(userId = 0, listOf(TileSpec.Invalid) + specs.toTileSpecs()) + + assertThat(loadTilesForUser(0)).isEqualTo(specs) + assertThat(tiles).isEqualTo(specs.toTileSpecs()) + } + + @Test + fun changeTiles_empty_noChanges() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + underTest.setTiles(userId = 0, emptyList()) + + assertThat(loadTilesForUser(0)).isNull() + assertThat(tiles).isEqualTo(getDefaultTileSpecs()) + } + + @Test + fun changeTiles_forCorrectUser() = + testScope.runTest { + val user0Tiles by collectLastValue(underTest.tilesSpecs(0)) + val user1Tiles by collectLastValue(underTest.tilesSpecs(1)) + + val specs = "a" + storeTilesForUser(specs, 0) + storeTilesForUser(specs, 1) + + underTest.setTiles(userId = 1, "b".toTileSpecs()) + + assertThat(loadTilesForUser(0)).isEqualTo("a") + assertThat(user0Tiles).isEqualTo(specs.toTileSpecs()) + + assertThat(loadTilesForUser(1)).isEqualTo("b") + assertThat(user1Tiles).isEqualTo("b".toTileSpecs()) + } + + @Test + fun multipleConcurrentRemovals_bothRemoved() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "a,b,c" + storeTilesForUser(specs, 0) + + coroutineScope { + underTest.removeTile(userId = 0, TileSpec.create("c")) + underTest.removeTile(userId = 0, TileSpec.create("a")) + } + + assertThat(loadTilesForUser(0)).isEqualTo("b") + assertThat(tiles).isEqualTo("b".toTileSpecs()) + } + + private fun getDefaultTileSpecs(): List<TileSpec> { + return QSHost.getDefaultSpecs(context.resources).map(TileSpec::create) + } + + private fun storeTilesForUser(specs: String, forUser: Int) { + secureSettings.putStringForUser(SETTING, specs, forUser) + } + + private fun loadTilesForUser(forUser: Int): String? { + return secureSettings.getStringForUser(SETTING, forUser) + } + + companion object { + private const val DEFAULT_TILES = "a,b,c" + private const val SETTING = Settings.Secure.QS_TILES + + private fun String.toTileSpecs(): List<TileSpec> { + return split(",").map(TileSpec::create) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt new file mode 100644 index 000000000000..d880172c1ba6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.shared + +import android.content.ComponentName +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class TileSpecTest : SysuiTestCase() { + + @Test + fun platformTile() { + val spec = "spec" + + val tileSpec = TileSpec.create(spec) + + assertThat(tileSpec is TileSpec.PlatformTileSpec).isTrue() + assertThat(tileSpec.spec).isEqualTo(spec) + } + + @Test + fun customTile() { + val componentName = ComponentName("test_pkg", "test_cls") + val spec = CUSTOM_TILE_PREFIX + componentName.flattenToString() + ")" + + val tileSpec = TileSpec.create(spec) + + assertThat(tileSpec is TileSpec.CustomTileSpec).isTrue() + assertThat(tileSpec.spec).isEqualTo(spec) + assertThat((tileSpec as TileSpec.CustomTileSpec).componentName).isEqualTo(componentName) + } + + @Test + fun emptyCustomTile_invalid() { + val spec = CUSTOM_TILE_PREFIX + ")" + + val tileSpec = TileSpec.create(spec) + + assertThat(tileSpec).isEqualTo(TileSpec.Invalid) + } + + @Test + fun invalidCustomTileSpec_invalid() { + val spec = CUSTOM_TILE_PREFIX + "invalid)" + + val tileSpec = TileSpec.create(spec) + + assertThat(tileSpec).isEqualTo(TileSpec.Invalid) + } + + @Test + fun customTileNotEndsWithParenthesis_invalid() { + val componentName = ComponentName("test_pkg", "test_cls") + val spec = CUSTOM_TILE_PREFIX + componentName.flattenToString() + + val tileSpec = TileSpec.create(spec) + + assertThat(tileSpec).isEqualTo(TileSpec.Invalid) + } + + @Test + fun emptySpec_invalid() { + assertThat(TileSpec.create("")).isEqualTo(TileSpec.Invalid) + } + + companion object { + private const val CUSTOM_TILE_PREFIX = "custom(" + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt index 71ba21538a8e..aa98f08e9015 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt @@ -167,6 +167,7 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) + captor.value.onBeforeUserSwitching(newID) captor.value.onUserSwitching(newID, userSwitchingReply) verify(userSwitchingReply).sendResult(any()) @@ -290,6 +291,7 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) + captor.value.onBeforeUserSwitching(newID) captor.value.onUserSwitching(newID, userSwitchingReply) verify(userSwitchingReply).sendResult(any()) @@ -308,6 +310,7 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) + captor.value.onBeforeUserSwitching(newID) captor.value.onUserSwitchComplete(newID) assertThat(callback.calledOnUserChanged).isEqualTo(1) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 7087c0135998..1bd13aadc1f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -162,6 +162,8 @@ import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.animation.FlingAnimationUtils; +import dagger.Lazy; + import org.junit.After; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -173,7 +175,6 @@ import org.mockito.stubbing.Answer; import java.util.List; import java.util.Optional; -import dagger.Lazy; import kotlinx.coroutines.CoroutineDispatcher; public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @@ -207,7 +208,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardStateController mKeyguardStateController; @Mock protected DozeLog mDozeLog; @Mock protected ShadeLogger mShadeLog; - @Mock protected ShadeHeightLogger mShadeHeightLogger; @Mock protected CommandQueue mCommandQueue; @Mock protected VibratorHelper mVibratorHelper; @Mock protected LatencyTracker mLatencyTracker; @@ -519,7 +519,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor, mMetricsLogger, mShadeLog, - mShadeHeightLogger, mConfigurationController, () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager, mConversationNotificationManager, mMediaHierarchyManager, @@ -578,7 +577,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mCentralSurfaces, null, () -> {}, - mNotificationShelfController); + mNotificationShelfController, + mHeadsUpManager); mNotificationPanelViewController.setTrackingStartedListener(() -> {}); mNotificationPanelViewController.setOpenCloseListener( new NotificationPanelViewController.OpenCloseListener() { @@ -588,7 +588,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Override public void onOpenStarted() {} }); - mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); verify(mView, atLeast(1)).addOnAttachStateChangeListener( @@ -601,7 +600,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mAccessibilityDelegate = accessibilityDelegateArgumentCaptor.getValue(); mNotificationPanelViewController.getStatusBarStateController() .addCallback(mNotificationPanelViewController.getStatusBarStateListener()); - mNotificationPanelViewController + mNotificationPanelViewController.getShadeHeadsUpTracker() .setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class)); verify(mNotificationStackScrollLayoutController) .setOnEmptySpaceClickListener(mEmptySpaceClickListenerCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index d36cc7e0ddbe..2db9c9788bf8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -456,6 +456,34 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test + public void keyguardStatusView_willPlayDelayedDoze_isCentered_thenNot() { + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + mStatusBarStateController.setState(KEYGUARD); + enableSplitShade(/* enabled= */ true); + + mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(true); + setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); + assertKeyguardStatusViewCentered(); + + mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(false); + assertKeyguardStatusViewNotCentered(); + } + + @Test + public void keyguardStatusView_willPlayDelayedDoze_isCentered_thenStillCenteredIfNoNotifs() { + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + mStatusBarStateController.setState(KEYGUARD); + enableSplitShade(/* enabled= */ true); + + mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(true); + setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); + assertKeyguardStatusViewCentered(); + + mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(false); + assertKeyguardStatusViewCentered(); + } + + @Test public void testCanCollapsePanelOnTouch_trueForKeyGuard() { mStatusBarStateController.setState(KEYGUARD); @@ -702,7 +730,8 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class); // Start fold animation & Capture Listeners - mNotificationPanelViewController.startFoldToAodAnimation(() -> {}, () -> {}, () -> {}); + mNotificationPanelViewController.getShadeFoldAnimator() + .startFoldToAodAnimation(() -> {}, () -> {}, () -> {}); verify(mViewPropertyAnimator).setListener(animCaptor.capture()); verify(mViewPropertyAnimator).setUpdateListener(updateCaptor.capture()); @@ -717,7 +746,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo enableSplitShade(/* enabled= */ true); mStatusBarStateController.setState(KEYGUARD); - mNotificationPanelViewController.expandWithQs(); + mNotificationPanelViewController.expandToQs(); verify(mLockscreenShadeTransitionController).goToLockedShade( /* expandedView= */null, /* needsQSAnimation= */true); @@ -798,7 +827,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void testQsExpansionChangedToDefaultWhenRotatingFromOrToSplitShade() { // to make sure shade is in expanded state - mNotificationPanelViewController.startWaitingForOpenPanelGesture(); + mNotificationPanelViewController.startWaitingForExpandGesture(); // switch to split shade from portrait (default state) enableSplitShade(/* enabled= */ true); @@ -817,7 +846,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo mNotificationPanelViewController.setExpandedFraction(1f); assertThat(mNotificationPanelViewController.isClosing()).isFalse(); - mNotificationPanelViewController.animateCloseQs(false); + mNotificationPanelViewController.animateCollapseQs(false); assertThat(mNotificationPanelViewController.isClosing()).isTrue(); } @@ -825,7 +854,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void getMaxPanelTransitionDistance_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() { enableSplitShade(true); - mNotificationPanelViewController.expandWithQs(); + mNotificationPanelViewController.expandToQs(); int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); @@ -835,7 +864,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void getMaxPanelTransitionDistance_inSplitShade_withHeadsUp_returnsBiggerValue() { enableSplitShade(true); - mNotificationPanelViewController.expandWithQs(); + mNotificationPanelViewController.expandToQs(); when(mHeadsUpManager.isTrackingHeadsUp()).thenReturn(true); when(mQsController.calculatePanelHeightExpanded(anyInt())).thenReturn(10000); mNotificationPanelViewController.setHeadsUpDraggingStartingHeight( @@ -852,7 +881,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo public void getMaxPanelTransitionDistance_expandingSplitShade_keyguard_returnsNonSplitShadeValue() { mStatusBarStateController.setState(KEYGUARD); enableSplitShade(true); - mNotificationPanelViewController.expandWithQs(); + mNotificationPanelViewController.expandToQs(); int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); @@ -862,7 +891,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void getMaxPanelTransitionDistance_expanding_notSplitShade_returnsNonSplitShadeValue() { enableSplitShade(false); - mNotificationPanelViewController.expandWithQs(); + mNotificationPanelViewController.expandToQs(); int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); @@ -1033,11 +1062,11 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo mStatusBarStateController.setState(SHADE); mNotificationPanelViewController.setExpandedHeight(0); - assertThat(mNotificationPanelViewController.isShadeFullyOpen()).isFalse(); + assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isFalse(); int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); mNotificationPanelViewController.setExpandedHeight(transitionDistance); - assertThat(mNotificationPanelViewController.isShadeFullyOpen()).isTrue(); + assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isTrue(); } @Test @@ -1046,12 +1075,12 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); mNotificationPanelViewController.setExpandedHeight(transitionDistance); - assertThat(mNotificationPanelViewController.isShadeFullyOpen()).isFalse(); + assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isFalse(); } @Test public void shadeExpanded_onShadeLocked() { mStatusBarStateController.setState(SHADE_LOCKED); - assertThat(mNotificationPanelViewController.isShadeFullyOpen()).isTrue(); + assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isTrue(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 006a7c735550..2a108239bac5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -177,7 +177,6 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { KeyguardTransitionInteractor( repository = FakeKeyguardTransitionRepository(), ), - bouncerInteractor = com.android.systemui.util.mockito.mock(), falsingManager = FalsingManagerFake(), ) }, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 1a52067e8306..86660a462c59 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -189,7 +189,6 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { KeyguardTransitionInteractor( repository = FakeKeyguardTransitionRepository(), ), - bouncerInteractor = mock(), falsingManager = FalsingManagerFake(), ) }, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index ab615f99ebad..932a1f9ca587 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -223,7 +223,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { fun testGoToLockedShadeCreatesQSAnimation() { transitionController.goToLockedShade(null) verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED) - verify(notificationPanelController).animateToFullShade(anyLong()) + verify(notificationPanelController).transitionToExpandedShade(anyLong()) assertNotNull(transitionController.dragDownAnimator) } @@ -231,7 +231,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { fun testGoToLockedShadeDoesntCreateQSAnimation() { transitionController.goToLockedShade(null, needsQSAnimation = false) verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED) - verify(notificationPanelController).animateToFullShade(anyLong()) + verify(notificationPanelController).transitionToExpandedShade(anyLong()) assertNull(transitionController.dragDownAnimator) } @@ -239,7 +239,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { fun testGoToLockedShadeAlwaysCreatesQSAnimationInSplitShade() { enableSplitShade() transitionController.goToLockedShade(null, needsQSAnimation = true) - verify(notificationPanelController).animateToFullShade(anyLong()) + verify(notificationPanelController).transitionToExpandedShade(anyLong()) assertNotNull(transitionController.dragDownAnimator) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt index 08a9f3139d71..7b59cc284181 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt @@ -22,7 +22,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.View import android.widget.FrameLayout -import androidx.core.animation.AnimatorTestRule +import androidx.core.animation.AnimatorTestRule2 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager @@ -70,7 +70,7 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { private lateinit var systemStatusAnimationScheduler: SystemStatusAnimationScheduler private val fakeFeatureFlags = FakeFeatureFlags() - @get:Rule val animatorTestRule = AnimatorTestRule() + @get:Rule val animatorTestRule = AnimatorTestRule2() @Before fun setup() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt index 7a6779684fc5..bef9fcb5697c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase; +import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogLevel import com.android.systemui.plugins.log.LogcatEchoTracker @@ -45,47 +45,130 @@ class NotificationWakeUpCoordinatorLoggerTest : SysuiTestCase() { } @Test - fun setDozeAmountWillThrottleFractionalUpdates() { - logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false) + fun updateVisibilityThrottleFractionalUpdates() { + logger.logSetVisibilityAmount(0f) verifyDidLog(1) - logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true) + logger.logSetVisibilityAmount(0.1f) verifyDidLog(1) - logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true) + logger.logSetVisibilityAmount(0.2f) + logger.logSetVisibilityAmount(0.3f) + logger.logSetVisibilityAmount(0.4f) + logger.logSetVisibilityAmount(0.5f) verifyDidLog(0) - logger.logSetDozeAmount(1f, 1f, "source1", StatusBarState.SHADE, changed = true) + logger.logSetVisibilityAmount(1f) verifyDidLog(1) } @Test - fun setDozeAmountWillIncludeFractionalUpdatesWhenStateChanges() { - logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false) + fun updateHideAmountThrottleFractionalOrRepeatedUpdates() { + logger.logSetHideAmount(0f) verifyDidLog(1) - logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true) + logger.logSetHideAmount(0f) + logger.logSetHideAmount(0f) + verifyDidLog(0) + logger.logSetHideAmount(0.1f) + verifyDidLog(1) + logger.logSetHideAmount(0.2f) + logger.logSetHideAmount(0.3f) + logger.logSetHideAmount(0.4f) + logger.logSetHideAmount(0.5f) + logger.logSetHideAmount(0.5f) + logger.logSetHideAmount(0.5f) + verifyDidLog(0) + logger.logSetHideAmount(1f) + verifyDidLog(1) + logger.logSetHideAmount(1f) + logger.logSetHideAmount(1f) + verifyDidLog(0) + } + + @Test + fun updateDozeAmountWillThrottleFractionalInputUpdates() { + logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.1f, 0f, null, 0.1f, StatusBarState.SHADE, changed = true) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.2f, 0f, null, 0.2f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.3f, 0f, null, 0.3f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.4f, 0f, null, 0.4f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true) + verifyDidLog(0) + logger.logUpdateDozeAmount(1f, 0f, null, 1f, StatusBarState.SHADE, changed = true) + verifyDidLog(1) + } + + @Test + fun updateDozeAmountWillThrottleFractionalDelayUpdates() { + logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false) + verifyDidLog(1) + logger.logUpdateDozeAmount(0f, 0.1f, null, 0.1f, StatusBarState.SHADE, changed = true) + verifyDidLog(1) + logger.logUpdateDozeAmount(0f, 0.2f, null, 0.2f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0f, 0.3f, null, 0.3f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0f, 0.4f, null, 0.4f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0f, 0.5f, null, 0.5f, StatusBarState.SHADE, changed = true) + verifyDidLog(0) + logger.logUpdateDozeAmount(0f, 1f, null, 1f, StatusBarState.SHADE, changed = true) verifyDidLog(1) - logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true) + } + + @Test + fun updateDozeAmountWillIncludeFractionalUpdatesWhenOtherInputChangesFractionality() { + logger.logUpdateDozeAmount(0.0f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.1f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.2f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false) + logger.logUpdateDozeAmount(0.3f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false) + logger.logUpdateDozeAmount(0.4f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false) + verifyDidLog(0) + logger.logUpdateDozeAmount(0.5f, 0.9f, 1f, 1f, StatusBarState.SHADE, changed = false) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.6f, 0.8f, 1f, 1f, StatusBarState.SHADE, changed = false) + logger.logUpdateDozeAmount(0.8f, 0.6f, 1f, 1f, StatusBarState.SHADE, changed = false) + logger.logUpdateDozeAmount(0.9f, 0.5f, 1f, 1f, StatusBarState.SHADE, changed = false) + verifyDidLog(0) + logger.logUpdateDozeAmount(1.0f, 0.4f, 1f, 1f, StatusBarState.SHADE, changed = false) + verifyDidLog(1) + logger.logUpdateDozeAmount(1.0f, 0.3f, 1f, 1f, StatusBarState.SHADE, changed = false) + logger.logUpdateDozeAmount(1.0f, 0.2f, 1f, 1f, StatusBarState.SHADE, changed = false) + logger.logUpdateDozeAmount(1.0f, 0.1f, 1f, 1f, StatusBarState.SHADE, changed = false) verifyDidLog(0) - logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.KEYGUARD, changed = false) + logger.logUpdateDozeAmount(1.0f, 0.0f, 1f, 1f, StatusBarState.SHADE, changed = false) verifyDidLog(1) } @Test - fun setDozeAmountWillIncludeFractionalUpdatesWhenSourceChanges() { - logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false) + fun updateDozeAmountWillIncludeFractionalUpdatesWhenStateChanges() { + logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false) verifyDidLog(1) - logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.1f, 0f, null, 0.1f, StatusBarState.SHADE, changed = true) verifyDidLog(1) - logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true) - logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.2f, 0f, null, 0.2f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.3f, 0f, null, 0.3f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.4f, 0f, null, 0.4f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true) verifyDidLog(0) - logger.logSetDozeAmount(0.5f, 0.5f, "source2", StatusBarState.SHADE, changed = false) + logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.KEYGUARD, changed = false) + verifyDidLog(1) + } + + @Test + fun updateDozeAmountWillIncludeFractionalUpdatesWhenHardOverrideChanges() { + logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.1f, 0f, null, 0.1f, StatusBarState.SHADE, changed = true) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.2f, 0f, null, 0.2f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.3f, 0f, null, 0.3f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.4f, 0f, null, 0.4f, StatusBarState.SHADE, changed = true) + logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true) + verifyDidLog(0) + logger.logUpdateDozeAmount(0.5f, 0f, 1f, 1f, StatusBarState.SHADE, changed = true) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.5f, 0f, 0f, 0f, StatusBarState.SHADE, changed = true) + verifyDidLog(1) + logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true) verifyDidLog(1) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt index 95591a4b321c..be3b7234a1a2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt @@ -17,31 +17,42 @@ package com.android.systemui.statusbar.notification import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.core.animation.AnimatorTestRule2 import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase; +import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.shade.NotificationPanelViewController.WAKEUP_ANIMATION_DELAY_MS import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_WAKEUP import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.policy.HeadsUpManager +import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.anyFloat import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions @RunWith(AndroidTestingRunner::class) @SmallTest +@TestableLooper.RunWithLooper(setAsMainLooper = true) class NotificationWakeUpCoordinatorTest : SysuiTestCase() { + @get:Rule val animatorTestRule = AnimatorTestRule2() + private val dumpManager: DumpManager = mock() private val headsUpManager: HeadsUpManager = mock() private val statusBarStateController: StatusBarStateController = mock() @@ -50,6 +61,7 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() { private val screenOffAnimationController: ScreenOffAnimationController = mock() private val logger: NotificationWakeUpCoordinatorLogger = mock() private val stackScrollerController: NotificationStackScrollLayoutController = mock() + private val wakeUpListener: NotificationWakeUpCoordinator.WakeUpListener = mock() private lateinit var notificationWakeUpCoordinator: NotificationWakeUpCoordinator private lateinit var statusBarStateCallback: StatusBarStateController.StateListener @@ -57,7 +69,8 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() { private var bypassEnabled: Boolean = false private var statusBarState: Int = StatusBarState.KEYGUARD - private var dozeAmount: Float = 0f + private fun eased(dozeAmount: Float) = + notificationWakeUpCoordinator.dozeAmountInterpolator.getInterpolation(dozeAmount) private fun setBypassEnabled(enabled: Boolean) { bypassEnabled = enabled @@ -70,7 +83,6 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() { } private fun setDozeAmount(dozeAmount: Float) { - this.dozeAmount = dozeAmount statusBarStateCallback.onDozeAmountChanged(dozeAmount, dozeAmount) } @@ -129,7 +141,7 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() { fun setDozeToZeroWithBypassWillFullyHideNotifications() { bypassEnabled = true setDozeAmount(0f) - verifyStackScrollerDozeAndHideAmount(dozeAmount = 01f, hideAmount = 1f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() } @@ -152,12 +164,161 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() { assertThat(notificationWakeUpCoordinator.statusBarState).isEqualTo(StatusBarState.SHADE) } + private val delayedDozeDelay = WAKEUP_ANIMATION_DELAY_MS.toLong() + private val delayedDozeDuration = ANIMATION_DURATION_WAKEUP.toLong() + + @Test + fun dozeAmountOutputClampsTo1WhenDelayStarts() { + notificationWakeUpCoordinator.setWakingUp(true, requestDelayedAnimation = true) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + + // verify further doze amount changes have no effect on output + setDozeAmount(0.5f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + } + + @Test + fun verifyDozeAmountOutputTracksDelay() { + dozeAmountOutputClampsTo1WhenDelayStarts() + + // Animator waiting the delay amount should not yet affect the output + animatorTestRule.advanceTimeBy(delayedDozeDelay) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + + // input doze amount change to 0 has no effect + setDozeAmount(0.0f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + + // Advancing the delay to 50% will cause the 50% output + animatorTestRule.advanceTimeBy(delayedDozeDuration / 2) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + + // Now advance delay to 100% completion; notifications become fully visible + animatorTestRule.advanceTimeBy(delayedDozeDuration / 2) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + + // Now advance delay to 200% completion -- should not invoke anything else + animatorTestRule.advanceTimeBy(delayedDozeDuration) + verify(stackScrollerController, never()).setDozeAmount(anyFloat()) + verify(stackScrollerController, never()).setHideAmount(anyFloat(), anyFloat()) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + } + + @Test + fun verifyWakeUpListenerCallbacksWhenDozing() { + // prime internal state as dozing, then add the listener + setDozeAmount(1f) + notificationWakeUpCoordinator.addListener(wakeUpListener) + + setDozeAmount(0.5f) + verify(wakeUpListener).onFullyHiddenChanged(eq(false)) + verifyNoMoreInteractions(wakeUpListener) + clearInvocations(wakeUpListener) + + setDozeAmount(0f) + verifyNoMoreInteractions(wakeUpListener) + + setDozeAmount(0.5f) + verifyNoMoreInteractions(wakeUpListener) + + setDozeAmount(1f) + verify(wakeUpListener).onFullyHiddenChanged(eq(true)) + verifyNoMoreInteractions(wakeUpListener) + } + + @Test + fun verifyWakeUpListenerCallbacksWhenDelayingAnimation() { + // prime internal state as dozing, then add the listener + setDozeAmount(1f) + notificationWakeUpCoordinator.addListener(wakeUpListener) + + // setWakingUp() doesn't do anything yet + notificationWakeUpCoordinator.setWakingUp(true, requestDelayedAnimation = true) + verifyNoMoreInteractions(wakeUpListener) + + // verify further doze amount changes have no effect + setDozeAmount(0.5f) + verifyNoMoreInteractions(wakeUpListener) + + // advancing to just before the start time should not invoke the listener + animatorTestRule.advanceTimeBy(delayedDozeDelay - 1) + verifyNoMoreInteractions(wakeUpListener) + + animatorTestRule.advanceTimeBy(1) + verify(wakeUpListener).onDelayedDozeAmountAnimationRunning(eq(true)) + verifyNoMoreInteractions(wakeUpListener) + clearInvocations(wakeUpListener) + + // input doze amount change to 0 has no effect + setDozeAmount(0.0f) + verifyNoMoreInteractions(wakeUpListener) + + // Advancing the delay to 50% will cause notifications to no longer be fully hidden + animatorTestRule.advanceTimeBy(delayedDozeDuration / 2) + verify(wakeUpListener).onFullyHiddenChanged(eq(false)) + verifyNoMoreInteractions(wakeUpListener) + clearInvocations(wakeUpListener) + + // Now advance delay to 99.x% completion; notifications become fully visible + animatorTestRule.advanceTimeBy(delayedDozeDuration / 2 - 1) + verifyNoMoreInteractions(wakeUpListener) + + // advance to 100%; animation no longer running + animatorTestRule.advanceTimeBy(1) + verify(wakeUpListener).onDelayedDozeAmountAnimationRunning(eq(false)) + verifyNoMoreInteractions(wakeUpListener) + clearInvocations(wakeUpListener) + + // Now advance delay to 200% completion -- should not invoke anything else + animatorTestRule.advanceTimeBy(delayedDozeDuration) + verifyNoMoreInteractions(wakeUpListener) + } + + @Test + fun verifyDelayedDozeAmountCanBeOverridden() { + dozeAmountOutputClampsTo1WhenDelayStarts() + + // input doze amount change to 0 has no effect + setDozeAmount(0.0f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + + // Advancing the delay to 50% will cause the 50% output + animatorTestRule.advanceTimeBy(delayedDozeDelay + delayedDozeDuration / 2) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + + // Enabling bypass and showing keyguard will override back to fully dozing/hidden + setBypassEnabled(true) + setStatusBarState(StatusBarState.KEYGUARD) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + } + + @Test + fun verifyRemovingOverrideRestoresOtherwiseCalculatedDozeAmount() { + verifyDelayedDozeAmountCanBeOverridden() + + // Disabling bypass will return back to the 50% value + setBypassEnabled(false) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + } + private fun verifyStackScrollerDozeAndHideAmount(dozeAmount: Float, hideAmount: Float) { // First verify that we did in-fact receive the correct values - verify(stackScrollerController).setDozeAmount(dozeAmount) - verify(stackScrollerController).setHideAmount(hideAmount, hideAmount) + verify(stackScrollerController).setDozeAmount(eased(dozeAmount)) + verify(stackScrollerController).setHideAmount(hideAmount, eased(hideAmount)) // Now verify that there was just this ONE call to each of these methods verify(stackScrollerController).setDozeAmount(anyFloat()) verify(stackScrollerController).setHideAmount(anyFloat(), anyFloat()) + // clear for next check + clearInvocations(stackScrollerController) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 9b6d29310d0b..b5e77e0fb693 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -16,14 +16,18 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE; + import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -31,6 +35,7 @@ import static org.mockito.Mockito.when; import static java.util.Objects.requireNonNull; +import android.database.ContentObserver; import android.os.Handler; import android.os.RemoteException; import android.testing.AndroidTestingRunner; @@ -295,6 +300,42 @@ public class PreparationCoordinatorTest extends SysuiTestCase { } @Test + public void testEntryCancellationWillRebindViews() { + // Configure NotifUiAdjustmentProvider to set up SHOW_NOTIFICATION_SNOOZE value + mEntry = spy(mEntry); + mAdjustmentProvider.addDirtyListener(mock(Runnable.class)); + when(mSecureSettings.getIntForUser(eq(SHOW_NOTIFICATION_SNOOZE), anyInt(), anyInt())) + .thenReturn(1); + ArgumentCaptor<ContentObserver> contentObserverCaptor = ArgumentCaptor.forClass( + ContentObserver.class); + verify(mSecureSettings).registerContentObserverForUser(eq(SHOW_NOTIFICATION_SNOOZE), + contentObserverCaptor.capture(), anyInt()); + ContentObserver contentObserver = contentObserverCaptor.getValue(); + contentObserver.onChange(false); + + // GIVEN an inflated notification + mCollectionListener.onEntryInit(mEntry); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + verify(mNotifInflater).inflateViews(eq(mEntry), any(), any()); + mNotifInflater.invokeInflateCallbackForEntry(mEntry); + + // Verify that snooze is initially enabled: from Settings & notification is not cancelled + assertTrue(mAdjustmentProvider.calculateAdjustment(mEntry).isSnoozeEnabled()); + + // WHEN notification is cancelled, rebind views because snooze enabled value changes + when(mEntry.isCanceled()).thenReturn(true); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + + assertFalse(mAdjustmentProvider.calculateAdjustment(mEntry).isSnoozeEnabled()); + + // THEN we rebind it + verify(mNotifInflater).rebindViews(eq(mEntry), any(), any()); + + // THEN we do not filter it because it's not the first inflation. + assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); + } + + @Test public void testDoesntFilterInflatedNotifs() { // GIVEN an inflated notification mCollectionListener.onEntryInit(mEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java index 50b3fc7e1c42..d5c0c5564af6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java @@ -25,6 +25,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -48,6 +50,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider; import com.android.systemui.statusbar.notification.collection.render.NodeController; @@ -75,12 +78,15 @@ public class RankingCoordinatorTest extends SysuiTestCase { @Mock private NodeController mAlertingHeaderController; @Mock private NodeController mSilentNodeController; @Mock private SectionHeaderController mSilentHeaderController; + @Mock private Pluggable.PluggableListener<NotifFilter> mInvalidationListener; @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor; + @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor; private NotificationEntry mEntry; private NotifFilter mCapturedSuspendedFilter; private NotifFilter mCapturedDozingFilter; + private StatusBarStateController.StateListener mStatusBarStateCallback; private RankingCoordinator mRankingCoordinator; private NotifSectioner mAlertingSectioner; @@ -106,6 +112,10 @@ public class RankingCoordinatorTest extends SysuiTestCase { verify(mNotifPipeline, times(2)).addPreGroupFilter(mNotifFilterCaptor.capture()); mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0); mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1); + mCapturedDozingFilter.setInvalidationListener(mInvalidationListener); + + verify(mStatusBarStateController, times(1)).addCallback(mStateListenerCaptor.capture()); + mStatusBarStateCallback = mStateListenerCaptor.getAllValues().get(0); mAlertingSectioner = mRankingCoordinator.getAlertingSectioner(); mSilentSectioner = mRankingCoordinator.getSilentSectioner(); @@ -170,6 +180,13 @@ public class RankingCoordinatorTest extends SysuiTestCase { // THEN don't filter out the notification assertFalse(mCapturedDozingFilter.shouldFilterOut(mEntry, 0)); + + // WHEN it's not dozing and doze amount is 1 + when(mStatusBarStateController.isDozing()).thenReturn(false); + when(mStatusBarStateController.getDozeAmount()).thenReturn(1f); + + // THEN filter out the notification + assertTrue(mCapturedDozingFilter.shouldFilterOut(mEntry, 0)); } @Test @@ -267,6 +284,27 @@ public class RankingCoordinatorTest extends SysuiTestCase { verify(mSilentHeaderController, times(2)).setClearSectionEnabled(eq(false)); } + @Test + public void statusBarStateCallbackTest() { + mStatusBarStateCallback.onDozeAmountChanged(1f, 1f); + verify(mInvalidationListener, times(1)) + .onPluggableInvalidated(mCapturedDozingFilter, "dozeAmount changed to one"); + reset(mInvalidationListener); + + mStatusBarStateCallback.onDozeAmountChanged(1f, 1f); + verify(mInvalidationListener, never()).onPluggableInvalidated(any(), any()); + reset(mInvalidationListener); + + mStatusBarStateCallback.onDozeAmountChanged(0.6f, 0.6f); + verify(mInvalidationListener, times(1)) + .onPluggableInvalidated(mCapturedDozingFilter, "dozeAmount changed to not one"); + reset(mInvalidationListener); + + mStatusBarStateCallback.onDozeAmountChanged(0f, 0f); + verify(mInvalidationListener, never()).onPluggableInvalidated(any(), any()); + reset(mInvalidationListener); + } + private void assertInSection(NotificationEntry entry, NotifSectioner section) { for (NotifSectioner current: mSections) { if (current == section) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java index 09b00e246eec..ae6ced410638 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java @@ -19,12 +19,14 @@ package com.android.systemui.statusbar.notification.interruption; import static android.app.Notification.FLAG_BUBBLE; import static android.app.Notification.FLAG_FOREGROUND_SERVICE; import static android.app.Notification.GROUP_ALERT_SUMMARY; +import static android.app.Notification.VISIBILITY_PRIVATE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE; import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; @@ -222,10 +224,26 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { ensureStateForHeadsUpWhenDozing(); NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); + modifyRanking(entry) + .setVisibilityOverride(VISIBILITY_NO_OVERRIDE) + .build(); + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue(); } @Test + public void testShouldHeadsUpWhenDozing_hiddenOnLockscreen() { + ensureStateForHeadsUpWhenDozing(); + + NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); + modifyRanking(entry) + .setVisibilityOverride(VISIBILITY_PRIVATE) + .build(); + + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); + } + + @Test public void testShouldNotHeadsUpWhenDozing_pulseDisabled() { // GIVEN state for "heads up when dozing" is true ensureStateForHeadsUpWhenDozing(); @@ -638,6 +656,39 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { } @Test + public void testShouldNotFullScreen_isSuppressedByBubbleMetadata_withStrictFlag() { + when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); + testShouldNotFullScreen_isSuppressedByBubbleMetadata(); + } + + @Test + public void testShouldNotFullScreen_isSuppressedByBubbleMetadata() { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") + .setSuppressNotification(true).build(); + entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); + when(mPowerManager.isInteractive()).thenReturn(false); + when(mStatusBarStateController.isDreaming()).thenReturn(true); + when(mStatusBarStateController.getState()).thenReturn(KEYGUARD); + + assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry)) + .isEqualTo(FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA); + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isFalse(); + verify(mLogger, never()).logNoFullscreen(any(), any()); + verify(mLogger).logNoFullscreenWarning(entry, + "NO_FSI_SUPPRESSIVE_BUBBLE_METADATA: BubbleMetadata may prevent HUN"); + verify(mLogger, never()).logFullscreen(any(), any()); + + assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1); + UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0); + assertThat(fakeUiEvent.eventId).isEqualTo( + NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA.getId()); + assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid()); + assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); + } + + @Test public void testShouldFullScreen_notInteractive_withStrictFlag() throws Exception { when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); testShouldFullScreen_notInteractive(); @@ -646,6 +697,9 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { @Test public void testShouldFullScreen_notInteractive() throws RemoteException { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") + .setSuppressNotification(false).build(); + entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); when(mPowerManager.isInteractive()).thenReturn(false); when(mStatusBarStateController.isDreaming()).thenReturn(false); when(mStatusBarStateController.getState()).thenReturn(SHADE); @@ -879,6 +933,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); Set<FullScreenIntentDecision> warnings = new HashSet<>(Arrays.asList( FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR, + FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA, FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD )); for (FullScreenIntentDecision decision : FullScreenIntentDecision.values()) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 3d8a74466a5c..4bb2c8740d44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -81,6 +81,7 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.wmshell.BubblesManager; @@ -134,6 +135,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private AssistantFeedbackController mAssistantFeedbackController; @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager; @Mock private StatusBarStateController mStatusBarStateController; + @Mock private HeadsUpManagerPhone mHeadsUpManagerPhone; @Before public void setUp() { @@ -153,7 +155,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mNotificationLockscreenUserManager, mStatusBarStateController, mDeviceProvisionedController, - mMetricsLogger); + mMetricsLogger, + mHeadsUpManagerPhone); mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); @@ -192,12 +195,15 @@ public class NotificationGutsManagerTest extends SysuiTestCase { anyInt(), anyBoolean(), any(Runnable.class)); + verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), true); assertEquals(View.VISIBLE, guts.getVisibility()); - mGutsManager.closeAndSaveGuts(false, false, false, 0, 0, false); + mGutsManager.closeAndSaveGuts(false, false, true, 0, 0, false); verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean()); verify(row, times(1)).setGutsView(any()); + mTestableLooper.processAllMessages(); + verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), false); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java index 824eb4aa25c2..551499e0fb55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -43,7 +43,6 @@ import android.view.ViewConfiguration; import androidx.test.filters.SmallTest; -import com.android.systemui.SwipeHelper; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.flags.FeatureFlags; @@ -101,7 +100,6 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { ViewConfiguration.get(mContext), new FalsingManagerFake(), mFeatureFlags, - SwipeHelper.X, mCallback, mListener, mNotificationRoundnessManager)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java index 31a1e4f9a4d9..775d2673ab18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java @@ -57,6 +57,8 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; +import dagger.Lazy; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -66,8 +68,6 @@ import org.mockito.stubbing.Answer; import java.util.Optional; -import dagger.Lazy; - @SmallTest @RunWith(AndroidTestingRunner.class) public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { @@ -153,7 +153,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { // Trying to open it does nothing. mSbcqCallbacks.animateExpandNotificationsPanel(); - verify(mNotificationPanelViewController, never()).expandShadeToNotifications(); + verify(mNotificationPanelViewController, never()).expandToNotifications(); mSbcqCallbacks.animateExpandSettingsPanel(null); verify(mNotificationPanelViewController, never()).expand(anyBoolean()); } @@ -171,9 +171,9 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { // Can now be opened. mSbcqCallbacks.animateExpandNotificationsPanel(); - verify(mNotificationPanelViewController).expandShadeToNotifications(); + verify(mNotificationPanelViewController).expandToNotifications(); mSbcqCallbacks.animateExpandSettingsPanel(null); - verify(mNotificationPanelViewController).expandWithQs(); + verify(mNotificationPanelViewController).expandToQs(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 7db219719bf0..32f0adfa1954 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -315,6 +315,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private ViewRootImpl mViewRootImpl; @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher; @Mock private UserTracker mUserTracker; + @Mock private FingerprintManager mFingerprintManager; @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback; @Mock IPowerManager mPowerManagerService; @@ -532,7 +533,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mCameraLauncherLazy, () -> mLightRevealScrimViewModel, mAlternateBouncerInteractor, - mUserTracker + mUserTracker, + () -> mFingerprintManager ) { @Override protected ViewRootImpl getViewRootImpl() { @@ -855,7 +857,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), mOnBackInvokedCallback.capture()); - when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true); + when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true); mOnBackInvokedCallback.getValue().onBackInvoked(); verify(mShadeController).animateCollapseShade(); } @@ -875,7 +877,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { OnBackAnimationCallback onBackAnimationCallback = (OnBackAnimationCallback) (mOnBackInvokedCallback.getValue()); - when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true); + when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true); BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 100.0f, 1.0f, BackEvent.EDGE_LEFT); onBackAnimationCallback.onBackProgressed(fakeSwipeInFromLeftEdge); @@ -897,7 +899,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { OnBackAnimationCallback onBackAnimationCallback = (OnBackAnimationCallback) (mOnBackInvokedCallback.getValue()); - when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true); + when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true); BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 10.0f, 0.0f, BackEvent.EDGE_LEFT); onBackAnimationCallback.onBackProgressed(fakeSwipeInFromLeftEdge); @@ -1233,7 +1235,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { setFoldedStates(FOLD_STATE_FOLDED); setGoToSleepStates(FOLD_STATE_FOLDED); mCentralSurfaces.setBarStateForTest(SHADE); - when(mNotificationPanelViewController.isShadeFullyOpen()).thenReturn(true); + when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(true); setDeviceState(FOLD_STATE_UNFOLDED); @@ -1245,7 +1247,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { setFoldedStates(FOLD_STATE_FOLDED); setGoToSleepStates(FOLD_STATE_FOLDED); mCentralSurfaces.setBarStateForTest(KEYGUARD); - when(mNotificationPanelViewController.isShadeFullyOpen()).thenReturn(true); + when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(true); setDeviceState(FOLD_STATE_UNFOLDED); @@ -1258,7 +1260,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { setFoldedStates(FOLD_STATE_FOLDED); setGoToSleepStates(FOLD_STATE_FOLDED); mCentralSurfaces.setBarStateForTest(SHADE); - when(mNotificationPanelViewController.isShadeFullyOpen()).thenReturn(false); + when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(false); setDeviceState(FOLD_STATE_UNFOLDED); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index e5e5d94ab595..3372dc3e7959 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -39,6 +39,7 @@ import com.android.systemui.flags.Flags; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; +import com.android.systemui.shade.ShadeHeadsUpTracker; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.HeadsUpStatusBarView; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; @@ -66,6 +67,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mock(NotificationStackScrollLayoutController.class); private final NotificationPanelViewController mPanelView = mock(NotificationPanelViewController.class); + private final ShadeHeadsUpTracker mShadeHeadsUpTracker = mock(ShadeHeadsUpTracker.class); private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class); private HeadsUpAppearanceController mHeadsUpAppearanceController; private NotificationTestHelper mTestHelper; @@ -102,6 +104,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mCommandQueue = mock(CommandQueue.class); mNotificationRoundnessManager = mock(NotificationRoundnessManager.class); mFeatureFlag = mock(FeatureFlags.class); + when(mPanelView.getShadeHeadsUpTracker()).thenReturn(mShadeHeadsUpTracker); when(mFeatureFlag.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)).thenReturn(true); mHeadsUpAppearanceController = new HeadsUpAppearanceController( mock(NotificationIconAreaController.class), @@ -212,15 +215,15 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { public void testDestroy() { reset(mHeadsUpManager); reset(mDarkIconDispatcher); - reset(mPanelView); + reset(mShadeHeadsUpTracker); reset(mStackScrollerController); mHeadsUpAppearanceController.onViewDetached(); verify(mHeadsUpManager).removeListener(any()); verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any()); - verify(mPanelView).removeTrackingHeadsUpListener(any()); - verify(mPanelView).setHeadsUpAppearanceController(isNull()); + verify(mShadeHeadsUpTracker).removeTrackingHeadsUpListener(any()); + verify(mShadeHeadsUpTracker).setHeadsUpAppearanceController(isNull()); verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 5bb25f5425a7..e83e50d65ae9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -45,6 +45,7 @@ import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.QuickSettingsController; import com.android.systemui.shade.ShadeController; +import com.android.systemui.shade.ShadeNotificationPresenter; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; @@ -110,9 +111,12 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotificationStackScrollLayout.class)); when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); + NotificationPanelViewController npvc = mock(NotificationPanelViewController.class); + when(npvc.getShadeNotificationPresenter()) + .thenReturn(mock(ShadeNotificationPresenter.class)); mStatusBarNotificationPresenter = new StatusBarNotificationPresenter( mContext, - mock(NotificationPanelViewController.class), + npvc, mock(QuickSettingsController.class), mock(HeadsUpManagerPhone.class), notificationShadeWindowView, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 0b2028532307..1fdcf7f27dbf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy +import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository @@ -89,6 +90,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { private val fakeNetworkEventsFlow = MutableStateFlow<FakeNetworkEventModel?>(null) private val mobileMappings = FakeMobileMappingsProxy() + private val subscriptionManagerProxy = FakeSubscriptionManagerProxy() private val scope = CoroutineScope(IMMEDIATE) @@ -117,6 +119,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { MobileConnectionsRepositoryImpl( connectivityRepository, subscriptionManager, + subscriptionManagerProxy, telephonyManager, logger, summaryLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index d65277f37ec4..ddff17aef2de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierCon import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy +import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl @@ -98,6 +99,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { @Mock private lateinit var logBufferFactory: TableLogBufferFactory private val mobileMappings = FakeMobileMappingsProxy() + private val subscriptionManagerProxy = FakeSubscriptionManagerProxy() private val scope = CoroutineScope(IMMEDIATE) @@ -179,6 +181,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { MobileConnectionsRepositoryImpl( connectivityRepository, subscriptionManager, + subscriptionManagerProxy, telephonyManager, logger, summaryLogger, @@ -662,6 +665,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { var latest: Int? = null val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this) + assertThat(latest).isEqualTo(INVALID_SUBSCRIPTION_ID) + fakeBroadcastDispatcher.registeredReceivers.forEach { receiver -> receiver.onReceive( context, @@ -686,6 +691,42 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } @Test + fun defaultDataSubId_fetchesInitialValueOnStart() = + runBlocking(IMMEDIATE) { + subscriptionManagerProxy.defaultDataSubId = 2 + var latest: Int? = null + val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(2) + + job.cancel() + } + + @Test + fun defaultDataSubId_fetchesCurrentOnRestart() = + runBlocking(IMMEDIATE) { + subscriptionManagerProxy.defaultDataSubId = 2 + var latest: Int? = null + var job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(2) + + job.cancel() + + // Collectors go away but come back later + + latest = null + + subscriptionManagerProxy.defaultDataSubId = 1 + + job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(1) + + job.cancel() + } + + @Test fun mobileIsDefault_startsAsFalse() { assertThat(underTest.mobileIsDefault.value).isFalse() } @@ -902,6 +943,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { MobileConnectionsRepositoryImpl( connectivityRepository, subscriptionManager, + subscriptionManagerProxy, telephonyManager, logger, summaryLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt new file mode 100644 index 000000000000..3dc7de688446 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.util + +import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID + +/** Fake of [SubscriptionManagerProxy] for easy testing */ +class FakeSubscriptionManagerProxy( + /** Set the default data subId to be returned in [getDefaultDataSubscriptionId] */ + var defaultDataSubId: Int = INVALID_SUBSCRIPTION_ID +) : SubscriptionManagerProxy { + override fun getDefaultDataSubscriptionId(): Int = defaultDataSubId +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt index 6980a0b4565e..6094135c6364 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt @@ -27,8 +27,10 @@ import com.android.systemui.settings.UserTracker import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.wrapper.BuildInfo import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -36,9 +38,9 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -58,6 +60,8 @@ class DeviceProvisionedControllerImplTest : SysuiTestCase() { private lateinit var dumpManager: DumpManager @Mock private lateinit var listener: DeviceProvisionedController.DeviceProvisionedListener + @Mock + private lateinit var buildInfo: BuildInfo @Captor private lateinit var userTrackerCallbackCaptor: ArgumentCaptor<UserTracker.Callback> @@ -72,12 +76,13 @@ class DeviceProvisionedControllerImplTest : SysuiTestCase() { mainExecutor = FakeExecutor(FakeSystemClock()) settings = FakeSettings() `when`(userTracker.userId).thenReturn(START_USER) - + whenever(buildInfo.isDebuggable).thenReturn(false) controller = DeviceProvisionedControllerImpl( settings, settings, userTracker, dumpManager, + buildInfo, Handler(testableLooper.looper), mainExecutor ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java index 391c8ca4d286..01e94baab7c3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java @@ -62,7 +62,7 @@ import android.window.OnBackInvokedDispatcher; import android.window.WindowOnBackInvokedDispatcher; import androidx.annotation.NonNull; -import androidx.core.animation.AnimatorTestRule; +import androidx.core.animation.AnimatorTestRule2; import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; @@ -110,7 +110,7 @@ public class RemoteInputViewTest extends SysuiTestCase { private final UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake(); @ClassRule - public static AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(); + public static AnimatorTestRule2 mAnimatorTestRule = new AnimatorTestRule2(); @Before public void setUp() throws Exception { diff --git a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java index 667099718788..eb932d29bf5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java @@ -110,13 +110,14 @@ public class TouchInsetManagerTest extends SysuiTestCase { clearInvocations(mAttachedSurfaceControl); when(view.isAttachedToWindow()).thenReturn(false); + when(view.getRootSurfaceControl()).thenReturn(null); // Trigger detachment and verify touchable region is set. listener.getValue().onViewDetachedFromWindow(view); mFakeExecutor.runAllReady(); - verify(mAttachedSurfaceControl).setTouchableRegion(any()); + verify(mAttachedSurfaceControl).setTouchableRegion(eq(null)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt index a87e61aae207..dfbd61bd057b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerReposito import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.shade.NotificationPanelViewController +import com.android.systemui.shade.ShadeFoldAnimator import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.phone.CentralSurfaces @@ -50,6 +51,8 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.`when` as whenever @@ -79,6 +82,8 @@ class FoldAodAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var commandQueue: CommandQueue + @Mock lateinit var shadeFoldAnimator: ShadeFoldAnimator + @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener> private lateinit var deviceStates: FoldableDeviceStates @@ -95,17 +100,17 @@ class FoldAodAnimationControllerTest : SysuiTestCase() { deviceStates = FoldableTestUtils.findDeviceStates(context) // TODO(b/254878364): remove this call to NPVC.getView() - whenever(notificationPanelViewController.view).thenReturn(viewGroup) + whenever(notificationPanelViewController.shadeFoldAnimator).thenReturn(shadeFoldAnimator) + whenever(shadeFoldAnimator.view).thenReturn(viewGroup) whenever(viewGroup.viewTreeObserver).thenReturn(viewTreeObserver) whenever(wakefulnessLifecycle.lastSleepReason) .thenReturn(PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD) whenever(centralSurfaces.notificationPanelViewController) .thenReturn(notificationPanelViewController) - whenever(notificationPanelViewController.startFoldToAodAnimation(any(), any(), any())) - .then { - val onActionStarted = it.arguments[0] as Runnable - onActionStarted.run() - } + whenever(shadeFoldAnimator.startFoldToAodAnimation(any(), any(), any())).then { + val onActionStarted = it.arguments[0] as Runnable + onActionStarted.run() + } keyguardRepository = FakeKeyguardRepository() val featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) } @@ -174,6 +179,28 @@ class FoldAodAnimationControllerTest : SysuiTestCase() { } @Test + fun onFolded_onScreenTurningOnInvokedTwice_doesNotLogLatency() = + runBlocking(IMMEDIATE) { + val job = underTest.listenForDozing(this) + keyguardRepository.setDozing(true) + setAodEnabled(enabled = true) + + yield() + + fold() + simulateScreenTurningOn() + reset(latencyTracker) + + // This can happen > 1 time if the prox sensor is covered + simulateScreenTurningOn() + + verify(latencyTracker, never()).onActionStart(any()) + verify(latencyTracker, never()).onActionEnd(any()) + + job.cancel() + } + + @Test fun onFolded_animationCancelled_doesNotLogLatency() = runBlocking(IMMEDIATE) { val job = underTest.listenForDozing(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt index 1ce25725b298..39ea46a657f2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt @@ -126,7 +126,7 @@ class TestUnfoldProgressListener : UnfoldTransitionProgressProvider.TransitionPr } fun assertLastProgress(progress: Float) { - assertThat(progressHistory.last()).isWithin(1.0E-4F).of(progress) + waitForCondition { progress == progressHistory.last() } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt index 8d74c82da6b0..adba53823d2c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.user.domain.interactor import android.app.ActivityManager import android.app.admin.DevicePolicyManager -import android.content.ComponentName import android.content.Intent import android.content.pm.UserInfo import android.graphics.Bitmap @@ -49,7 +48,6 @@ import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.domain.interactor.TelephonyInteractor -import com.android.systemui.user.UserSwitcherActivity import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.source.UserRecord @@ -58,11 +56,9 @@ import com.android.systemui.user.shared.model.UserActionModel import com.android.systemui.user.shared.model.UserModel import com.android.systemui.user.utils.MultiUserActionsEvent import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.kotlinArgumentCaptor import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertNotNull @@ -842,7 +838,7 @@ class UserInteractorTest : SysuiTestCase() { fun `show user switcher - full screen disabled - shows dialog switcher`() = testScope.runTest { val expandable = mock<Expandable>() - underTest.showUserSwitcher(context, expandable) + underTest.showUserSwitcher(expandable) val dialogRequest = collectLastValue(underTest.dialogShowRequests) @@ -855,30 +851,22 @@ class UserInteractorTest : SysuiTestCase() { } @Test - fun `show user switcher - full screen enabled - launches activity`() { - featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) - - val expandable = mock<Expandable>() - underTest.showUserSwitcher(context, expandable) - - // Dialog is shown. - val intentCaptor = argumentCaptor<Intent>() - verify(activityStarter) - .startActivity( - intentCaptor.capture(), - /* dismissShade= */ eq(true), - /* ActivityLaunchAnimator.Controller= */ nullable(), - /* showOverLockscreenWhenLocked= */ eq(true), - eq(UserHandle.SYSTEM), - ) - assertThat(intentCaptor.value.component) - .isEqualTo( - ComponentName( - context, - UserSwitcherActivity::class.java, - ) - ) - } + fun `show user switcher - full screen enabled - launches full screen dialog`() = + testScope.runTest { + featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) + + val expandable = mock<Expandable>() + underTest.showUserSwitcher(expandable) + + val dialogRequest = collectLastValue(underTest.dialogShowRequests) + + // Dialog is shown. + assertThat(dialogRequest()) + .isEqualTo(ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog(expandable)) + + underTest.onDialogShown() + assertThat(dialogRequest()).isNull() + } @Test fun `users - secondary user - managed profile is not included`() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt index 7780a4372976..a342dadcb775 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt @@ -34,8 +34,6 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerReposito import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.power.data.repository.FakePowerRepository -import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.telephony.data.repository.FakeTelephonyRepository @@ -88,7 +86,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() { private lateinit var userRepository: FakeUserRepository private lateinit var keyguardRepository: FakeKeyguardRepository - private lateinit var powerRepository: FakePowerRepository private lateinit var testDispatcher: TestDispatcher private lateinit var testScope: TestScope @@ -116,7 +113,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() { } keyguardRepository = FakeKeyguardRepository() - powerRepository = FakePowerRepository() val refreshUsersScheduler = RefreshUsersScheduler( applicationScope = testScope.backgroundScope, @@ -145,7 +141,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() { set(Flags.FACE_AUTH_REFACTOR, true) } underTest = - UserSwitcherViewModel.Factory( + UserSwitcherViewModel( userInteractor = UserInteractor( applicationContext = context, @@ -174,13 +170,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() { guestUserInteractor = guestUserInteractor, uiEventLogger = uiEventLogger, ), - powerInteractor = - PowerInteractor( - repository = powerRepository, - ), guestUserInteractor = guestUserInteractor, ) - .create(UserSwitcherViewModel::class.java) } @Test @@ -327,46 +318,12 @@ class UserSwitcherViewModelTest : SysuiTestCase() { } @Test - fun `isFinishRequested - finishes when user is switched`() = - testScope.runTest { - val userInfos = setUsers(count = 2) - val isFinishRequested = mutableListOf<Boolean>() - val job = - launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } - assertThat(isFinishRequested.last()).isFalse() - - userRepository.setSelectedUserInfo(userInfos[1]) - - assertThat(isFinishRequested.last()).isTrue() - - job.cancel() - } - - @Test - fun `isFinishRequested - finishes when the screen turns off`() = - testScope.runTest { - setUsers(count = 2) - powerRepository.setInteractive(true) - val isFinishRequested = mutableListOf<Boolean>() - val job = - launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } - assertThat(isFinishRequested.last()).isFalse() - - powerRepository.setInteractive(false) - - assertThat(isFinishRequested.last()).isTrue() - - job.cancel() - } - - @Test fun `isFinishRequested - finishes when cancel button is clicked`() = testScope.runTest { setUsers(count = 2) - powerRepository.setInteractive(true) val isFinishRequested = mutableListOf<Boolean>() val job = - launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } + launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } assertThat(isFinishRequested.last()).isFalse() underTest.onCancelButtonClicked() diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index cc3b4ab0fb4e..28bdca97552d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -57,6 +57,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; +import android.content.pm.ShortcutInfo; import android.content.pm.UserInfo; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -100,6 +101,7 @@ import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shade.ShadeWindowLogger; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.statusbar.NotificationEntryHelper; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -123,7 +125,6 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.bubbles.Bubble; import com.android.wm.shell.bubbles.BubbleBadgeIconFactory; @@ -135,6 +136,7 @@ import com.android.wm.shell.bubbles.BubbleLogger; import com.android.wm.shell.bubbles.BubbleStackView; import com.android.wm.shell.bubbles.BubbleViewInfoTask; import com.android.wm.shell.bubbles.Bubbles; +import com.android.wm.shell.bubbles.StackEducationViewKt; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; @@ -145,6 +147,7 @@ import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.taskview.TaskViewTransitions; import org.junit.After; import org.junit.Before; @@ -1669,6 +1672,60 @@ public class BubblesTest extends SysuiTestCase { } @Test + public void testShowStackEdu_isNotConversationBubble() { + // Setup + setPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION, false); + BubbleEntry bubbleEntry = createBubbleEntry(false /* isConversation */); + mBubbleController.updateBubble(bubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Click on bubble + Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey()); + assertFalse(bubble.isConversation()); + bubble.getIconView().callOnClick(); + + // Check education is not shown + BubbleStackView stackView = mBubbleController.getStackView(); + assertFalse(stackView.isStackEduVisible()); + } + + @Test + public void testShowStackEdu_isConversationBubble() { + // Setup + setPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION, false); + BubbleEntry bubbleEntry = createBubbleEntry(true /* isConversation */); + mBubbleController.updateBubble(bubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Click on bubble + Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey()); + assertTrue(bubble.isConversation()); + bubble.getIconView().callOnClick(); + + // Check education is shown + BubbleStackView stackView = mBubbleController.getStackView(); + assertTrue(stackView.isStackEduVisible()); + } + + @Test + public void testShowStackEdu_isSeenConversationBubble() { + // Setup + setPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION, true); + BubbleEntry bubbleEntry = createBubbleEntry(true /* isConversation */); + mBubbleController.updateBubble(bubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Click on bubble + Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey()); + assertTrue(bubble.isConversation()); + bubble.getIconView().callOnClick(); + + // Check education is not shown + BubbleStackView stackView = mBubbleController.getStackView(); + assertFalse(stackView.isStackEduVisible()); + } + + @Test public void testShowOrHideAppBubble_addsAndExpand() { assertThat(mBubbleController.isStackExpanded()).isFalse(); assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull(); @@ -1816,6 +1873,20 @@ public class BubblesTest extends SysuiTestCase { mock(Bubbles.PendingIntentCanceledListener.class), new SyncExecutor()); } + private BubbleEntry createBubbleEntry(boolean isConversation) { + NotificationEntry notificationEntry = mNotificationTestHelper.createBubble(mDeleteIntent); + if (isConversation) { + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) + .setId("shortcutId") + .build(); + NotificationEntryHelper.modifyRanking(notificationEntry) + .setIsConversation(true) + .setShortcutInfo(shortcutInfo) + .build(); + } + return mBubblesManager.notifToBubbleEntry(notificationEntry); + } + /** Creates a context that will return a PackageManager with specific AppInfo. */ private Context setUpContextWithPackageManager(String pkg, ApplicationInfo info) throws Exception { @@ -1852,6 +1923,15 @@ public class BubblesTest extends SysuiTestCase { bubbleMetadata.setFlags(flags); } + /** + * Set preferences boolean value for key + * Used to setup global state for stack view education tests + */ + private void setPrefBoolean(String key, boolean enabled) { + mContext.getSharedPreferences(mContext.getPackageName(), Context.MODE_PRIVATE) + .edit().putBoolean(key, enabled).apply(); + } + private Notification.BubbleMetadata getMetadata() { Intent target = new Intent(mContext, BubblesTestActivity.class); PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, FLAG_MUTABLE); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java index 317928516c03..c3bb7716d9a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java @@ -25,7 +25,6 @@ import android.view.WindowManager; import com.android.internal.statusbar.IStatusBarService; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.bubbles.BubbleData; @@ -42,6 +41,7 @@ import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.taskview.TaskViewTransitions; import java.util.Optional; diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt index e1ba074ac860..ce8d93e2a0e7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt @@ -69,10 +69,10 @@ fun <T> TestScope.collectValues( flow: Flow<T>, context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, -): FlowValues<T> { +): FlowValue<List<T>> { val values = mutableListOf<T>() backgroundScope.launch(context, start) { flow.collect(values::add) } - return FlowValuesImpl { + return FlowValueImpl { runCurrent() values.toList() } @@ -83,17 +83,7 @@ interface FlowValue<T> : ReadOnlyProperty<Any?, T> { operator fun invoke(): T } -/** @see collectValues */ -interface FlowValues<T> : ReadOnlyProperty<Any?, List<T>> { - operator fun invoke(): List<T> -} - private class FlowValueImpl<T>(private val block: () -> T) : FlowValue<T> { override operator fun invoke(): T = block() override fun getValue(thisRef: Any?, property: KProperty<*>): T = invoke() } - -private class FlowValuesImpl<T>(private val block: () -> List<T>) : FlowValues<T> { - override operator fun invoke(): List<T> = block() - override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> = invoke() -} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt index d4b1701892c7..d8b3270d3aff 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt @@ -46,6 +46,10 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository { override val isFaceAuthSupportedInCurrentPosture: Flow<Boolean> get() = flowOf(true) + private val _isCurrentUserInLockdown = MutableStateFlow(false) + override val isCurrentUserInLockdown: Flow<Boolean> + get() = _isCurrentUserInLockdown + fun setFingerprintEnrolled(isFingerprintEnrolled: Boolean) { _isFingerprintEnrolled.value = isFingerprintEnrolled } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt index 5641832b6ae2..00b1a401ac79 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt @@ -17,14 +17,22 @@ package com.android.systemui.keyguard.data.repository +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository { - private val _isLockedOut = MutableStateFlow<Boolean>(false) + private val _isLockedOut = MutableStateFlow(false) override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow() + private val _isRunning = MutableStateFlow(false) + override val isRunning: Flow<Boolean> + get() = _isRunning + + override val availableFpSensorType: BiometricType? + get() = null + fun setLockedOut(lockedOut: Boolean) { _isLockedOut.value = lockedOut } diff --git a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java index fa30a6f419f9..e6055148867d 100644 --- a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java +++ b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java @@ -123,11 +123,9 @@ class FlashNotificationsController { private static final int SCREEN_DEFAULT_COLOR_WITH_ALPHA = SCREEN_DEFAULT_COLOR | SCREEN_DEFAULT_ALPHA; - // TODO(b/266775677): Make protected-broadcast intent @VisibleForTesting static final String ACTION_FLASH_NOTIFICATION_START_PREVIEW = "com.android.internal.intent.action.FLASH_NOTIFICATION_START_PREVIEW"; - // TODO(b/266775677): Make protected-broadcast intent @VisibleForTesting static final String ACTION_FLASH_NOTIFICATION_STOP_PREVIEW = "com.android.internal.intent.action.FLASH_NOTIFICATION_STOP_PREVIEW"; @@ -143,13 +141,10 @@ class FlashNotificationsController { @VisibleForTesting static final int PREVIEW_TYPE_LONG = 1; - // TODO(b/266775683): Move to settings provider @VisibleForTesting static final String SETTING_KEY_CAMERA_FLASH_NOTIFICATION = "camera_flash_notification"; - // TODO(b/266775683): Move to settings provider @VisibleForTesting static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION = "screen_flash_notification"; - // TODO(b/266775683): Move to settings provider @VisibleForTesting static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR = "screen_flash_notification_color_global"; diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java index eba92305dd7b..c89b9b851742 100644 --- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java +++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java @@ -266,11 +266,11 @@ public class SystemActionPerformer { // actions. switch (actionId) { case AccessibilityService.GLOBAL_ACTION_BACK: { - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK, InputDevice.SOURCE_KEYBOARD); return true; } case AccessibilityService.GLOBAL_ACTION_HOME: { - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME, InputDevice.SOURCE_KEYBOARD); return true; } case AccessibilityService.GLOBAL_ACTION_RECENTS: @@ -291,23 +291,29 @@ public class SystemActionPerformer { return lockScreen(); case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT: return takeScreenshot(); - case AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK : - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK); + case AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK: + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK, + InputDevice.SOURCE_KEYBOARD); return true; case AccessibilityService.GLOBAL_ACTION_DPAD_UP: - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP); + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP, + InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD); return true; case AccessibilityService.GLOBAL_ACTION_DPAD_DOWN: - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_DOWN); + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_DOWN, + InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD); return true; case AccessibilityService.GLOBAL_ACTION_DPAD_LEFT: - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT); + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT, + InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD); return true; case AccessibilityService.GLOBAL_ACTION_DPAD_RIGHT: - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT); + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT, + InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD); return true; case AccessibilityService.GLOBAL_ACTION_DPAD_CENTER: - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER); + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER, + InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD); return true; default: Slog.e(TAG, "Invalid action id: " + actionId); @@ -318,23 +324,24 @@ public class SystemActionPerformer { } } - private void sendDownAndUpKeyEvents(int keyCode) { + private void sendDownAndUpKeyEvents(int keyCode, int source) { final long token = Binder.clearCallingIdentity(); try { // Inject down. final long downTime = SystemClock.uptimeMillis(); - sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime); + sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime, source); sendKeyEventIdentityCleared( - keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis()); + keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis(), source); } finally { Binder.restoreCallingIdentity(token); } } - private void sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time) { + private void sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time, + int source) { KeyEvent event = KeyEvent.obtain(downTime, time, action, keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, - InputDevice.SOURCE_KEYBOARD, null); + source, null); mContext.getSystemService(InputManager.class) .injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); event.recycle(); diff --git a/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java b/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java index 3b30af69d02b..06a616c3f348 100644 --- a/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java +++ b/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java @@ -74,6 +74,9 @@ public final class FillRequestEventLogger { public static final int TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE = AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE; + // Augmented autofill currently doesn't have an assigned request_id, use -2 as the magic number. + public static final int AUGMENTED_AUTOFILL_REQUEST_ID = -2; + private final int mSessionId; private Optional<FillRequestEventInternal> mEventInternal; @@ -102,6 +105,7 @@ public final class FillRequestEventLogger { /** * Set request_id as long as mEventInternal presents. + * For the case of Augmented Autofill, set to -2. */ public void maybeSetRequestId(int requestId) { mEventInternal.ifPresent(event -> event.mRequestId = requestId); diff --git a/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java new file mode 100644 index 000000000000..6b8246cd5bfb --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.autofill; + +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_CANCELLED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_FAILURE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SESSION_DESTROYED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SUCCESS; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_TIMEOUT; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_UNKNOWN; +import static com.android.server.autofill.Helper.sVerbose; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.service.autofill.Dataset; +import android.text.TextUtils; +import android.util.Slog; +import android.view.autofill.AutofillId; + +import com.android.internal.util.FrameworkStatsLog; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Optional; + +/** + * Helper class to log Autofill FillResponse stats. + */ +public final class FillResponseEventLogger { + private static final String TAG = "FillResponseEventLogger"; + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillRequestReported.RequestTriggerReason}. + */ + @IntDef(prefix = {"DISPLAY_PRESENTATION_TYPE"}, value = { + DISPLAY_PRESENTATION_TYPE_UNKNOWN, + DISPLAY_PRESENTATION_TYPE_MENU, + DISPLAY_PRESENTATION_TYPE_INLINE, + DISPLAY_PRESENTATION_TYPE_DIALOG + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisplayPresentationType { + } + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillResponseReported.AuthenticationType}. + */ + @IntDef(prefix = {"AUTHENTICATION_TYPE"}, value = { + AUTHENTICATION_TYPE_UNKNOWN, + AUTHENTICATION_TYPE_DATASET_AHTHENTICATION, + AUTHENTICATION_TYPE_FULL_AHTHENTICATION + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AuthenticationType { + } + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillResponseReported.FillResponseStatus}. + */ + @IntDef(prefix = {"RESPONSE_STATUS"}, value = { + RESPONSE_STATUS_UNKNOWN, + RESPONSE_STATUS_FAILURE, + RESPONSE_STATUS_SUCCESS, + RESPONSE_STATUS_CANCELLED, + RESPONSE_STATUS_TIMEOUT, + RESPONSE_STATUS_SESSION_DESTROYED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResponseStatus { + } + + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillResponseReported.AuthenticationResult}. + */ + @IntDef(prefix = {"AUTHENTICATION_RESULT"}, value = { + AUTHENTICATION_RESULT_UNKNOWN, + AUTHENTICATION_RESULT_SUCCESS, + AUTHENTICATION_RESULT_FAILURE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AuthenticationResult { + } + + public static final int DISPLAY_PRESENTATION_TYPE_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; + public static final int DISPLAY_PRESENTATION_TYPE_MENU = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; + public static final int DISPLAY_PRESENTATION_TYPE_INLINE = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; + public static final int DISPLAY_PRESENTATION_TYPE_DIALOG = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; + public static final int AUTHENTICATION_TYPE_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; + public static final int AUTHENTICATION_TYPE_DATASET_AHTHENTICATION = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; + public static final int AUTHENTICATION_TYPE_FULL_AHTHENTICATION = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; + + public static final int AUTHENTICATION_RESULT_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; + public static final int AUTHENTICATION_RESULT_SUCCESS = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; + public static final int AUTHENTICATION_RESULT_FAILURE = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; + public static final int RESPONSE_STATUS_TIMEOUT = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_TIMEOUT; + public static final int RESPONSE_STATUS_CANCELLED = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_CANCELLED; + public static final int RESPONSE_STATUS_FAILURE = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_FAILURE; + public static final int RESPONSE_STATUS_SESSION_DESTROYED = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SESSION_DESTROYED; + public static final int RESPONSE_STATUS_SUCCESS = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SUCCESS; + public static final int RESPONSE_STATUS_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_UNKNOWN; + + // Log a magic number when FillRequest failed or timeout to differentiate with FillRequest + // succeeded. + public static final int AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT = -1; + + private final int mSessionId; + private Optional<FillResponseEventInternal> mEventInternal; + + private FillResponseEventLogger(int sessionId) { + mSessionId = sessionId; + mEventInternal = Optional.empty(); + } + + /** + * A factory constructor to create FillResponseEventLogger. + */ + public static FillResponseEventLogger forSessionId(int sessionId) { + return new FillResponseEventLogger(sessionId); + } + + /** + * Reset mEventInternal before logging for a new response. It shall be called + * for each FillResponse. + */ + public void startLogForNewResponse() { + if (!mEventInternal.isEmpty()) { + Slog.w(TAG, "FillResponseEventLogger is not empty before starting " + + "for a new request"); + } + mEventInternal = Optional.of(new FillResponseEventInternal()); + } + + /** + * Set request_id as long as mEventInternal presents. + */ + public void maybeSetRequestId(int val) { + mEventInternal.ifPresent(event -> event.mRequestId = val); + } + + /** + * Set app_package_uid as long as mEventInternal presents. + */ + public void maybeSetAppPackageUid(int val) { + mEventInternal.ifPresent(event -> { + event.mAppPackageUid = val; + }); + } + + /** + * Set display_presentation_type as long as mEventInternal presents. + */ + public void maybeSetDisplayPresentationType(@DisplayPresentationType int val) { + mEventInternal.ifPresent(event -> { + event.mDisplayPresentationType = val; + }); + } + + /** + * Set available_count as long as mEventInternal presents. + * For cases of FillRequest failed and timeout, set to -1. + */ + public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList, + AutofillId currentViewId) { + mEventInternal.ifPresent(event -> { + int availableCount = getDatasetCountForAutofillId(datasetList, currentViewId); + event.mAvailableCount = availableCount; + }); + } + + public void maybeSetAvailableCount(int val) { + mEventInternal.ifPresent(event -> { + event.mAvailableCount = val; + }); + } + + private static int getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList, + AutofillId currentViewId) { + int availableCount = 0; + if (datasetList != null) { + for (int i = 0; i < datasetList.size(); i++) { + Dataset data = datasetList.get(i); + if (data != null && data.getFieldIds() != null + && data.getFieldIds().contains(currentViewId)) { + availableCount += 1; + } + } + } + return availableCount; + } + + /** + * Set save_ui_trigger_ids as long as mEventInternal presents. + */ + public void maybeSetSaveUiTriggerIds(int val) { + mEventInternal.ifPresent(event -> { + event.mSaveUiTriggerIds = val; + }); + } + + /** + * Set latency_fill_response_received_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyFillResponseReceivedMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyFillResponseReceivedMillis = val; + }); + } + + /** + * Set authentication_type as long as mEventInternal presents. + */ + public void maybeSetAuthenticationType(@AuthenticationType int val) { + mEventInternal.ifPresent(event -> { + event.mAuthenticationType = val; + }); + } + + /** + * Set authentication_result as long as mEventInternal presents. + */ + public void maybeSetAuthenticationResult(@AuthenticationResult int val) { + mEventInternal.ifPresent(event -> { + event.mAuthenticationResult = val; + }); + } + + /** + * Set authentication_failure_reason as long as mEventInternal presents. + */ + public void maybeSetAuthenticationFailureReason(int val) { + mEventInternal.ifPresent(event -> { + event.mAuthenticationFailureReason = val; + }); + } + + /** + * Set latency_authentication_ui_display_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyAuthenticationUiDisplayMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyAuthenticationUiDisplayMillis = val; + }); + } + + /** + * Set latency_dataset_display_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyDatasetDisplayMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyDatasetDisplayMillis = val; + }); + } + + /** + * Set response_status as long as mEventInternal presents. + */ + public void maybeSetResponseStatus(@ResponseStatus int val) { + mEventInternal.ifPresent(event -> { + event.mResponseStatus = val; + }); + } + + /** + * Set latency_response_processing_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyResponseProcessingMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyResponseProcessingMillis = val; + }); + } + + + /** + * Log an AUTOFILL_FILL_RESPONSE_REPORTED event. + */ + public void logAndEndEvent() { + if (!mEventInternal.isPresent()) { + Slog.w(TAG, "Shouldn't be logging AutofillFillRequestReported again for same " + + "event"); + return; + } + FillResponseEventInternal event = mEventInternal.get(); + if (sVerbose) { + Slog.v(TAG, "Log AutofillFillResponseReported:" + + " requestId=" + event.mRequestId + + " sessionId=" + mSessionId + + " mAppPackageUid=" + event.mAppPackageUid + + " mDisplayPresentationType=" + event.mDisplayPresentationType + + " mAvailableCount=" + event.mAvailableCount + + " mSaveUiTriggerIds=" + event.mSaveUiTriggerIds + + " mLatencyFillResponseReceivedMillis=" + event.mLatencyFillResponseReceivedMillis + + " mAuthenticationType=" + event.mAuthenticationType + + " mAuthenticationResult=" + event.mAuthenticationResult + + " mAuthenticationFailureReason=" + event.mAuthenticationFailureReason + + " mLatencyAuthenticationUiDisplayMillis=" + event.mLatencyAuthenticationUiDisplayMillis + + " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis + + " mResponseStatus=" + event.mResponseStatus + + " mLatencyResponseProcessingMillis=" + event.mLatencyResponseProcessingMillis); + } + FrameworkStatsLog.write( + AUTOFILL_FILL_RESPONSE_REPORTED, + event.mRequestId, + mSessionId, + event.mAppPackageUid, + event.mDisplayPresentationType, + event.mAvailableCount, + event.mSaveUiTriggerIds, + event.mLatencyFillResponseReceivedMillis, + event.mAuthenticationType, + event.mAuthenticationResult, + event.mAuthenticationFailureReason, + event.mLatencyAuthenticationUiDisplayMillis, + event.mLatencyDatasetDisplayMillis, + event.mResponseStatus, + event.mLatencyResponseProcessingMillis); + mEventInternal = Optional.empty(); + } + + private static final class FillResponseEventInternal { + int mRequestId = -1; + int mAppPackageUid = -1; + int mDisplayPresentationType = DISPLAY_PRESENTATION_TYPE_UNKNOWN; + int mAvailableCount = 0; + int mSaveUiTriggerIds = -1; + int mLatencyFillResponseReceivedMillis = 0; + int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN; + int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN; + int mAuthenticationFailureReason = -1; + int mLatencyAuthenticationUiDisplayMillis = 0; + int mLatencyDatasetDisplayMillis = 0; + int mResponseStatus = RESPONSE_STATUS_UNKNOWN; + int mLatencyResponseProcessingMillis = 0; + + FillResponseEventInternal() { + } + } +} diff --git a/services/autofill/java/com/android/server/autofill/SaveEventLogger.java b/services/autofill/java/com/android/server/autofill/SaveEventLogger.java new file mode 100644 index 000000000000..4b7d5bdf0002 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/SaveEventLogger.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.autofill; + +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_DATASET_MATCH; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_FIELD_VALIDATION_FAILED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_HAS_EMPTY_REQUIRED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NONE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_SAVE_INFO; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_VALUE_CHANGED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_UNKNOWN; +import static com.android.server.autofill.Helper.sVerbose; + +import android.annotation.IntDef; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.internal.util.FrameworkStatsLog; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Optional; + +/** + * Helper class to log Autofill Save event stats. + */ +public final class SaveEventLogger { + private static final String TAG = "SaveEventLogger"; + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillSaveEventReported.SaveUiShownReason}. + */ + @IntDef(prefix = {"SAVE_UI_SHOWN_REASON"}, value = { + SAVE_UI_SHOWN_REASON_UNKNOWN, + SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE, + SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE, + SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SaveUiShownReason { + } + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillSaveEventReported.SaveUiNotShownReason}. + */ + @IntDef(prefix = {"SAVE_UI_NOT_SHOWN_REASON"}, value = { + NO_SAVE_REASON_UNKNOWN, + NO_SAVE_REASON_NONE, + NO_SAVE_REASON_NO_SAVE_INFO, + NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG, + NO_SAVE_REASON_HAS_EMPTY_REQUIRED, + NO_SAVE_REASON_NO_VALUE_CHANGED, + NO_SAVE_REASON_FIELD_VALIDATION_FAILED, + NO_SAVE_REASON_DATASET_MATCH + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SaveUiNotShownReason { + } + + public static final int SAVE_UI_SHOWN_REASON_UNKNOWN = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_UNKNOWN; + public static final int SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE; + public static final int SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE; + public static final int SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET; + + public static final int NO_SAVE_REASON_UNKNOWN = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_UNKNOWN; + public static final int NO_SAVE_REASON_NONE = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NONE; + public static final int NO_SAVE_REASON_NO_SAVE_INFO = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_SAVE_INFO; + public static final int NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG; + public static final int NO_SAVE_REASON_HAS_EMPTY_REQUIRED = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_HAS_EMPTY_REQUIRED; + public static final int NO_SAVE_REASON_NO_VALUE_CHANGED = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_VALUE_CHANGED; + public static final int NO_SAVE_REASON_FIELD_VALIDATION_FAILED = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_FIELD_VALIDATION_FAILED; + public static final int NO_SAVE_REASON_DATASET_MATCH = + AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_DATASET_MATCH; + + private final int mSessionId; + private Optional<SaveEventInternal> mEventInternal; + + private SaveEventLogger(int sessionId) { + mSessionId = sessionId; + mEventInternal = Optional.of(new SaveEventInternal()); + } + + /** + * A factory constructor to create FillRequestEventLogger. + */ + public static SaveEventLogger forSessionId(int sessionId) { + return new SaveEventLogger(sessionId); + } + + /** + * Set request_id as long as mEventInternal presents. + */ + public void maybeSetRequestId(int requestId) { + mEventInternal.ifPresent(event -> event.mRequestId = requestId); + } + + /** + * Set app_package_uid as long as mEventInternal presents. + */ + public void maybeSetAppPackageUid(int val) { + mEventInternal.ifPresent(event -> { + event.mAppPackageUid = val; + }); + } + + /** + * Set save_ui_trigger_ids as long as mEventInternal presents. + */ + public void maybeSetSaveUiTriggerIds(int val) { + mEventInternal.ifPresent(event -> { + event.mSaveUiTriggerIds = val; + }); + } + + /** + * Set flag as long as mEventInternal presents. + */ + public void maybeSetFlag(int val) { + mEventInternal.ifPresent(event -> { + event.mFlag = val; + }); + } + + /** + * Set is_new_field as long as mEventInternal presents. + */ + public void maybeSetIsNewField(boolean val) { + mEventInternal.ifPresent(event -> { + event.mIsNewField = val; + }); + } + + /** + * Set save_ui_shown_reason as long as mEventInternal presents. + */ + public void maybeSetSaveUiShownReason(@SaveUiShownReason int reason) { + mEventInternal.ifPresent(event -> { + event.mSaveUiShownReason = reason; + }); + } + + /** + * Set save_ui_not_shown_reason as long as mEventInternal presents. + */ + public void maybeSetSaveUiNotShownReason(@SaveUiNotShownReason int reason) { + mEventInternal.ifPresent(event -> { + event.mSaveUiNotShownReason = reason; + }); + } + + /** + * Set save_button_clicked as long as mEventInternal presents. + */ + public void maybeSetSaveButtonClicked(boolean val) { + mEventInternal.ifPresent(event -> { + event.mSaveButtonClicked = val; + }); + } + + /** + * Set cancel_button_clicked as long as mEventInternal presents. + */ + public void maybeSetCancelButtonClicked(boolean val) { + mEventInternal.ifPresent(event -> { + event.mCancelButtonClicked = val; + }); + } + + /** + * Set dialog_dismissed as long as mEventInternal presents. + */ + public void maybeSetDialogDismissed(boolean val) { + mEventInternal.ifPresent(event -> { + event.mDialogDismissed = val; + }); + } + + /** + * Set is_saved as long as mEventInternal presents. + */ + public void maybeSetIsSaved(boolean val) { + mEventInternal.ifPresent(event -> { + event.mIsSaved = val; + }); + } + + /** + * Set latency_save_ui_display_millis as long as mEventInternal presents. + */ + public void maybeSetLatencySaveUiDisplayMillis(long timestamp) { + mEventInternal.ifPresent(event -> { + event.mLatencySaveUiDisplayMillis = timestamp; + }); + } + + /** + * Set latency_save_request_millis as long as mEventInternal presents. + */ + public void maybeSetLatencySaveRequestMillis(long timestamp) { + mEventInternal.ifPresent(event -> { + event.mLatencySaveRequestMillis = timestamp; + }); + } + + /** + * Set latency_save_finish_millis as long as mEventInternal presents. + */ + public void maybeSetLatencySaveFinishMillis(long timestamp) { + mEventInternal.ifPresent(event -> { + event.mLatencySaveFinishMillis = timestamp; + }); + } + + /** + * Log an AUTOFILL_SAVE_EVENT_REPORTED event. + */ + public void logAndEndEvent() { + if (!mEventInternal.isPresent()) { + Slog.w(TAG, "Shouldn't be logging AutofillSaveEventReported again for same " + + "event"); + return; + } + SaveEventInternal event = mEventInternal.get(); + if (sVerbose) { + Slog.v(TAG, "Log AutofillSaveEventReported:" + + " requestId=" + event.mRequestId + + " sessionId=" + mSessionId + + " mAppPackageUid=" + event.mAppPackageUid + + " mSaveUiTriggerIds=" + event.mSaveUiTriggerIds + + " mFlag=" + event.mFlag + + " mIsNewField=" + event.mIsNewField + + " mSaveUiShownReason=" + event.mSaveUiShownReason + + " mSaveUiNotShownReason=" + event.mSaveUiNotShownReason + + " mSaveButtonClicked=" + event.mSaveButtonClicked + + " mCancelButtonClicked=" + event.mCancelButtonClicked + + " mDialogDismissed=" + event.mDialogDismissed + + " mIsSaved=" + event.mIsSaved + + " mLatencySaveUiDisplayMillis=" + event.mLatencySaveUiDisplayMillis + + " mLatencySaveRequestMillis=" + event.mLatencySaveRequestMillis + + " mLatencySaveFinishMillis=" + event.mLatencySaveFinishMillis); + } + FrameworkStatsLog.write( + AUTOFILL_SAVE_EVENT_REPORTED, + event.mRequestId, + mSessionId, + event.mAppPackageUid, + event.mSaveUiTriggerIds, + event.mFlag, + event.mIsNewField, + event.mSaveUiShownReason, + event.mSaveUiNotShownReason, + event.mSaveButtonClicked, + event.mCancelButtonClicked, + event.mDialogDismissed, + event.mIsSaved, + event.mLatencySaveUiDisplayMillis, + event.mLatencySaveRequestMillis, + event.mLatencySaveFinishMillis); + mEventInternal = Optional.empty(); + } + + private static final class SaveEventInternal { + int mRequestId; + int mAppPackageUid = -1; + int mSaveUiTriggerIds = -1; + long mFlag = -1; + boolean mIsNewField = false; + int mSaveUiShownReason = SAVE_UI_SHOWN_REASON_UNKNOWN; + int mSaveUiNotShownReason = NO_SAVE_REASON_UNKNOWN; + boolean mSaveButtonClicked = false; + boolean mCancelButtonClicked = false; + boolean mDialogDismissed = false; + boolean mIsSaved = false; + long mLatencySaveUiDisplayMillis = 0; + long mLatencySaveRequestMillis = 0; + long mLatencySaveFinishMillis = 0; + + SaveEventInternal() { + } + } +} diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 4acdabec92f4..46fc7628aae4 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -41,9 +41,16 @@ import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import static com.android.server.autofill.FillRequestEventLogger.AUGMENTED_AUTOFILL_REQUEST_ID; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_NORMAL_TRIGGER; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_PRE_TRIGGER; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE; +import static com.android.server.autofill.FillResponseEventLogger.AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_FAILURE; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SUCCESS; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_FAILURE; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_TIMEOUT; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SESSION_DESTROYED; import static com.android.server.autofill.Helper.containsCharsInOrder; import static com.android.server.autofill.Helper.createSanitizers; import static com.android.server.autofill.Helper.getNumericValue; @@ -446,6 +453,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private FillRequestEventLogger mFillRequestEventLogger; + @NonNull + @GuardedBy("mLock") + private FillResponseEventLogger mFillResponseEventLogger; + /** * Fill dialog request would likely be sent slightly later. */ @@ -1122,8 +1133,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + ", flags=" + flags + ")"); } mSessionFlags.mAugmentedAutofillOnly = true; - // Augmented autofill doesn't have request_id. - mFillRequestEventLogger.maybeSetRequestId(-1); + mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID); mFillRequestEventLogger.maybeSetIsAugmented(mSessionFlags.mAugmentedAutofillOnly); mFillRequestEventLogger.logAndEndEvent(); triggerAugmentedAutofillLocked(flags); @@ -1166,7 +1176,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // structure is taken. This causes only one fill request per burst of focus changes. cancelCurrentRequestLocked(); - if (mClassificationState.mHintsToAutofillIdMap == null) { + if (mService.getMaster().isPccClassificationEnabled() + && mClassificationState.mHintsToAutofillIdMap == null) { if (sVerbose) { Slog.v(TAG, "triggering field classification"); } @@ -1315,6 +1326,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mSessionState = STATE_ACTIVE; mPresentationStatsEventLogger = PresentationStatsEventLogger.forSessionId(sessionId); mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId); + mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId); synchronized (mLock) { mSessionFlags = new SessionFlags(); mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly; @@ -1421,24 +1433,35 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // FillServiceCallbacks @Override + @SuppressWarnings("GuardedBy") public void onFillRequestSuccess(int requestId, @Nullable FillResponse response, @NonNull String servicePackageName, int requestFlags) { final AutofillId[] fieldClassificationIds; final LogMaker requestLog; + // Start a new FillResponse logger for the success case. + mFillResponseEventLogger.startLogForNewResponse(); + mFillResponseEventLogger.maybeSetRequestId(requestId); + mFillResponseEventLogger.maybeSetAppPackageUid(uid); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SUCCESS); + // Time passed since session was created + final long fillRequestReceivedRelativeTimestamp = + SystemClock.elapsedRealtime() - mLatencyBaseTime; + mPresentationStatsEventLogger.maybeSetFillResponseReceivedTimestampMs( + (int) (fillRequestReceivedRelativeTimestamp)); + mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis( + (int) (fillRequestReceivedRelativeTimestamp)); + synchronized (mLock) { if (mDestroyed) { Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: " + id + " destroyed"); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED); + mFillResponseEventLogger.logAndEndEvent(); return; } - // Time passed since session was created - final long fillRequestReceivedRelativeTimestamp = - SystemClock.elapsedRealtime() - mLatencyBaseTime; - mPresentationStatsEventLogger.maybeSetFillResponseReceivedTimestampMs( - (int) (fillRequestReceivedRelativeTimestamp)); requestLog = mRequestLogs.get(requestId); if (requestLog != null) { @@ -1844,11 +1867,23 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // fallback to the default platform password manager mSessionFlags.mClientSuggestionsEnabled = false; mLastFillDialogTriggerIds = null; + // Log the existing FillResponse event. + mFillResponseEventLogger.logAndEndEvent(); final InlineSuggestionsRequest inlineRequest = (mLastInlineSuggestionsRequest != null && mLastInlineSuggestionsRequest.first == requestId) ? mLastInlineSuggestionsRequest.second : null; + + // Start a new FillRequest logger for client suggestion fallback. + mFillRequestEventLogger.startLogForNewRequest(); + mFillRequestEventLogger.maybeSetAppPackageUid(uid); + mFillRequestEventLogger.maybeSetFlags( + flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS); + mFillRequestEventLogger.maybeSetRequestTriggerReason( + TRIGGER_REASON_NORMAL_TRIGGER); + mFillRequestEventLogger.maybeSetIsClientSuggestionFallback(true); + mAssistReceiver.newAutofillRequestLocked(inlineRequest); requestAssistStructureLocked(requestId, flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS); @@ -1857,24 +1892,42 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // FillServiceCallbacks @Override + @SuppressWarnings("GuardedBy") public void onFillRequestFailure(int requestId, @Nullable CharSequence message) { onFillRequestFailureOrTimeout(requestId, false, message); } // FillServiceCallbacks @Override + @SuppressWarnings("GuardedBy") public void onFillRequestTimeout(int requestId) { onFillRequestFailureOrTimeout(requestId, true, null); } + @SuppressWarnings("GuardedBy") private void onFillRequestFailureOrTimeout(int requestId, boolean timedOut, @Nullable CharSequence message) { boolean showMessage = !TextUtils.isEmpty(message); + + // Start a new FillResponse logger for the failure or timeout case. + mFillResponseEventLogger.startLogForNewResponse(); + mFillResponseEventLogger.maybeSetRequestId(requestId); + mFillResponseEventLogger.maybeSetAppPackageUid(uid); + mFillResponseEventLogger.maybeSetAvailableCount( + AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT); + final long fillRequestReceivedRelativeTimestamp = + SystemClock.elapsedRealtime() - mLatencyBaseTime; + mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis( + (int)(fillRequestReceivedRelativeTimestamp)); + synchronized (mLock) { unregisterDelayedFillBroadcastLocked(); if (mDestroyed) { Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId + ") rejected - session: " + id + " destroyed"); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED); + mFillResponseEventLogger.logAndEndEvent(); + return; } if (sDebug) { @@ -1905,11 +1958,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (timedOut) { mPresentationStatsEventLogger.maybeSetNoPresentationEventReason( NOT_SHOWN_REASON_REQUEST_TIMEOUT); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_TIMEOUT); } else { mPresentationStatsEventLogger.maybeSetNoPresentationEventReason( NOT_SHOWN_REASON_REQUEST_FAILED); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_FAILURE); } mPresentationStatsEventLogger.logAndEndEvent(); + mFillResponseEventLogger.logAndEndEvent(); } notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED, /* autofillableIds= */ null); @@ -4455,7 +4511,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.w(TAG, "processNullResponseLocked(): no context for req " + requestId); autofillableIds = null; } - + // Log the existing FillResponse event. + mFillResponseEventLogger.logAndEndEvent(); mService.resetLastResponse(); // The default autofill service cannot fulfill the request, let's check if the augmented @@ -4560,6 +4617,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + getSmartSuggestionModeToString(mode) + " when server returned null for session " + this.id); } + // Log FillRequest for Augmented Autofill. + mFillRequestEventLogger.startLogForNewRequest(); + mFillRequestEventLogger.maybeSetAppPackageUid(uid); + mFillRequestEventLogger.maybeSetFlags(mFlags); + mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID); + mFillRequestEventLogger.logAndEndEvent(); final ViewState viewState = mViewStates.get(mCurrentViewId); viewState.setState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL); @@ -4677,6 +4740,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mPresentationStatsEventLogger.maybeSetAvailableCount( newResponse.getDatasets(), mCurrentViewId); + mFillResponseEventLogger.maybeSetAvailableCount( + newResponse.getDatasets(), mCurrentViewId); setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, false); updateFillDialogTriggerIdsLocked(); diff --git a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java new file mode 100644 index 000000000000..92d72ac828f3 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.autofill; + +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_ACTIVITY_FINISHED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CHANGED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CLICKED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_COMMITTED; +import static com.android.server.autofill.Helper.sVerbose; + +import android.annotation.IntDef; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.internal.util.FrameworkStatsLog; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Optional; + +/** + * Helper class to log Autofill session committed event stats. + */ +public final class SessionCommittedEventLogger { + private static final String TAG = "SessionCommittedEventLogger"; + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillSessionCommitted.AutofillCommitReason}. + */ + @IntDef(prefix = {"COMMIT_REASON"}, value = { + COMMIT_REASON_UNKNOWN, + COMMIT_REASON_ACTIVITY_FINISHED, + COMMIT_REASON_VIEW_COMMITTED, + COMMIT_REASON_VIEW_CLICKED, + COMMIT_REASON_VIEW_CHANGED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CommitReason { + } + + public static final int COMMIT_REASON_UNKNOWN = + AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_UNKNOWN; + public static final int COMMIT_REASON_ACTIVITY_FINISHED = + AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_ACTIVITY_FINISHED; + public static final int COMMIT_REASON_VIEW_COMMITTED = + AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_COMMITTED; + public static final int COMMIT_REASON_VIEW_CLICKED = + AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CLICKED; + public static final int COMMIT_REASON_VIEW_CHANGED = + AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CHANGED; + + private final int mSessionId; + private Optional<SessionCommittedEventInternal> mEventInternal; + + private SessionCommittedEventLogger(int sessionId) { + mSessionId = sessionId; + mEventInternal = Optional.of(new SessionCommittedEventInternal()); + } + + /** + * A factory constructor to create SessionCommittedEventLogger. + */ + public static SessionCommittedEventLogger forSessionId(int sessionId) { + return new SessionCommittedEventLogger(sessionId); + } + + /** + * Set component_package_uid as long as mEventInternal presents. + */ + public void maybeSetComponentPackageUid(int val) { + mEventInternal.ifPresent(event -> { + event.mComponentPackageUid = val; + }); + } + + /** + * Set request_count as long as mEventInternal presents. + */ + public void maybeSetRequestCount(int val) { + mEventInternal.ifPresent(event -> { + event.mRequestCount = val; + }); + } + + /** + * Set commit_reason as long as mEventInternal presents. + */ + public void maybeSetCommitReason(@CommitReason int val) { + mEventInternal.ifPresent(event -> { + event.mCommitReason = val; + }); + } + + /** + * Set session_duration_millis as long as mEventInternal presents. + */ + public void maybeSetSessionDurationMillis(long timestamp) { + mEventInternal.ifPresent(event -> { + event.mSessionDurationMillis = timestamp; + }); + } + + /** + * Log an AUTOFILL_SESSION_COMMITTED event. + */ + public void logAndEndEvent() { + if (!mEventInternal.isPresent()) { + Slog.w(TAG, "Shouldn't be logging AutofillSessionCommitted again for same session."); + return; + } + SessionCommittedEventInternal event = mEventInternal.get(); + if (sVerbose) { + Slog.v(TAG, "Log AutofillSessionCommitted:" + + " sessionId=" + mSessionId + + " mComponentPackageUid=" + event.mComponentPackageUid + + " mRequestCount=" + event.mRequestCount + + " mCommitReason=" + event.mCommitReason + + " mSessionDurationMillis=" + event.mSessionDurationMillis); + } + FrameworkStatsLog.write( + AUTOFILL_SESSION_COMMITTED, + mSessionId, + event.mComponentPackageUid, + event.mRequestCount, + event.mCommitReason, + event.mSessionDurationMillis); + mEventInternal = Optional.empty(); + } + + private static final class SessionCommittedEventInternal { + int mComponentPackageUid = -1; + int mRequestCount = 0; + int mCommitReason = COMMIT_REASON_UNKNOWN; + long mSessionDurationMillis = 0; + + SessionCommittedEventInternal() { + } + } +} diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java index 990dd64434a0..1a0588e999e2 100644 --- a/services/companion/java/com/android/server/companion/virtual/InputController.java +++ b/services/companion/java/com/android/server/companion/virtual/InputController.java @@ -93,7 +93,8 @@ class InputController { /* Token -> file descriptor associations. */ @GuardedBy("mLock") - private final Map<IBinder, InputDeviceDescriptor> mInputDeviceDescriptors = new ArrayMap<>(); + private final ArrayMap<IBinder, InputDeviceDescriptor> mInputDeviceDescriptors = + new ArrayMap<>(); private final Handler mHandler; private final NativeWrapper mNativeWrapper; @@ -303,7 +304,8 @@ class InputController { @GuardedBy("mLock") private void updateActivePointerDisplayIdLocked() { InputDeviceDescriptor mostRecentlyCreatedMouse = null; - for (InputDeviceDescriptor otherInputDeviceDescriptor : mInputDeviceDescriptors.values()) { + for (int i = 0; i < mInputDeviceDescriptors.size(); ++i) { + InputDeviceDescriptor otherInputDeviceDescriptor = mInputDeviceDescriptors.valueAt(i); if (otherInputDeviceDescriptor.isMouse()) { if (mostRecentlyCreatedMouse == null || (otherInputDeviceDescriptor.getCreationOrderNumber() @@ -338,10 +340,8 @@ class InputController { } synchronized (mLock) { - InputDeviceDescriptor[] values = mInputDeviceDescriptors.values().toArray( - new InputDeviceDescriptor[0]); - for (InputDeviceDescriptor value : values) { - if (value.mName.equals(deviceName)) { + for (int i = 0; i < mInputDeviceDescriptors.size(); ++i) { + if (mInputDeviceDescriptors.valueAt(i).mName.equals(deviceName)) { throw new DeviceCreationException( "Input device name already in use: " + deviceName); } @@ -473,7 +473,8 @@ class InputController { fout.println(" InputController: "); synchronized (mLock) { fout.println(" Active descriptors: "); - for (InputDeviceDescriptor inputDeviceDescriptor : mInputDeviceDescriptors.values()) { + for (int i = 0; i < mInputDeviceDescriptors.size(); ++i) { + InputDeviceDescriptor inputDeviceDescriptor = mInputDeviceDescriptors.valueAt(i); fout.println(" ptr: " + inputDeviceDescriptor.getNativePointer()); fout.println(" displayId: " + inputDeviceDescriptor.getDisplayId()); fout.println(" creationOrder: " diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index e0d1c1e70b34..73dbb86ae7cc 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -73,6 +73,9 @@ import android.content.pm.ProviderInfo; import android.content.pm.UserInfo; import android.content.res.ObbInfo; import android.database.ContentObserver; +import android.media.MediaCodecList; +import android.media.MediaCodecInfo; +import android.media.MediaFormat; import android.net.Uri; import android.os.BatteryManager; import android.os.Binder; @@ -954,10 +957,27 @@ class StorageManagerService extends IStorageManager.Stub } } + private boolean isHevcDecoderSupported() { + MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS); + MediaCodecInfo[] codecInfos = codecList.getCodecInfos(); + for (MediaCodecInfo codecInfo : codecInfos) { + if (codecInfo.isEncoder()) { + continue; + } + String[] supportedTypes = codecInfo.getSupportedTypes(); + for (String type : supportedTypes) { + if (type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { + return true; + } + } + } + return false; + } + private void configureTranscoding() { // See MediaProvider TranscodeHelper#getBooleanProperty for more information boolean transcodeEnabled = false; - boolean defaultValue = true; + boolean defaultValue = isHevcDecoderSupported() ? true : false; if (SystemProperties.getBoolean("persist.sys.fuse.transcode_user_control", false)) { transcodeEnabled = SystemProperties.getBoolean("persist.sys.fuse.transcode_enabled", diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java index 7f24c52ccc6b..3d3535d2dbd2 100644 --- a/services/core/java/com/android/server/SystemServerInitThreadPool.java +++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java @@ -25,7 +25,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.Preconditions; -import com.android.server.am.ActivityManagerService; +import com.android.server.am.StackTracesDumpHelper; import com.android.server.utils.TimingsTraceAndSlog; import java.io.PrintWriter; @@ -188,12 +188,12 @@ public final class SystemServerInitThreadPool implements Dumpable { } /** - * A helper function to call ActivityManagerService.dumpStackTraces(). + * A helper function to call StackTracesDumpHelper.dumpStackTraces(). */ private static void dumpStackTraces() { final ArrayList<Integer> pids = new ArrayList<>(); pids.add(Process.myPid()); - ActivityManagerService.dumpStackTraces(pids, + StackTracesDumpHelper.dumpStackTraces(pids, /* processCpuTracker= */null, /* lastPids= */null, CompletableFuture.completedFuture(Watchdog.getInterestingNativePids()), /* logExceptionCreatingFile= */null, /* subject= */null, diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index f652cb050cbd..78d4708e70a2 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -1104,7 +1104,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final NetworkCapabilities result = ncBuilder.build(); final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy( mTrackingNetworkCallback - .requiresRestartForImmutableCapabilityChanges(result), + .requiresRestartForImmutableCapabilityChanges(result, linkProperties), result); logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities @@ -1354,19 +1354,29 @@ public class VcnManagementService extends IVcnManagementService.Stub { * without requiring a Network restart. */ private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback { + private final Object mLockObject = new Object(); private final Map<Network, NetworkCapabilities> mCaps = new ArrayMap<>(); + private final Map<Network, LinkProperties> mLinkProperties = new ArrayMap<>(); @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) { - synchronized (mCaps) { + synchronized (mLockObject) { mCaps.put(network, caps); } } @Override + public void onLinkPropertiesChanged(Network network, LinkProperties lp) { + synchronized (mLockObject) { + mLinkProperties.put(network, lp); + } + } + + @Override public void onLost(Network network) { - synchronized (mCaps) { + synchronized (mLockObject) { mCaps.remove(network); + mLinkProperties.remove(network); } } @@ -1393,22 +1403,28 @@ public class VcnManagementService extends IVcnManagementService.Stub { return true; } - private boolean requiresRestartForImmutableCapabilityChanges(NetworkCapabilities caps) { + private boolean requiresRestartForImmutableCapabilityChanges( + NetworkCapabilities caps, LinkProperties lp) { if (caps.getSubscriptionIds() == null) { return false; } - synchronized (mCaps) { - for (NetworkCapabilities existing : mCaps.values()) { - if (caps.getSubscriptionIds().equals(existing.getSubscriptionIds()) - && hasSameTransportsAndCapabilities(caps, existing)) { - // Restart if any immutable capabilities have changed - return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) + synchronized (mLockObject) { + // Search for an existing network (using interfce names) + // TODO: Get network from NetworkFactory (if exists) for this match. + for (Entry<Network, LinkProperties> lpEntry : mLinkProperties.entrySet()) { + if (lp.getInterfaceName() != null + && !lp.getInterfaceName().isEmpty() + && Objects.equals( + lp.getInterfaceName(), lpEntry.getValue().getInterfaceName())) { + return mCaps.get(lpEntry.getKey()) + .hasCapability(NET_CAPABILITY_NOT_RESTRICTED) != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED); } } } + // If no network found, by definition does not need restart. return false; } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 03821db3e43f..62651dd80cd9 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -56,6 +56,7 @@ import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.ZygoteConnectionConstants; import com.android.internal.util.FrameworkStatsLog; import com.android.server.am.ActivityManagerService; +import com.android.server.am.StackTracesDumpHelper; import com.android.server.am.TraceErrorLogger; import com.android.server.criticalevents.CriticalEventLog; import com.android.server.wm.SurfaceAnimationThread; @@ -905,7 +906,7 @@ public class Watchdog implements Dumpable { report.append(ResourcePressureUtil.currentPsiState()); ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(false); StringWriter tracesFileException = new StringWriter(); - final File stack = ActivityManagerService.dumpStackTraces( + final File stack = StackTracesDumpHelper.dumpStackTraces( pids, processCpuTracker, new SparseBooleanArray(), CompletableFuture.completedFuture(getInterestingNativePids()), tracesFileException, subject, criticalEvents, Runnable::run, /* latencyTracker= */null); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index a60f06a60d93..51d349f542d1 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -5086,7 +5086,6 @@ public class AccountManagerService @Override public void onServiceDisconnected(ComponentName name) { - mAuthenticator = null; IAccountManagerResponse response = getResponseAndClose(); if (response != null) { try { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 461103ee4355..8fe61e719817 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -73,6 +73,7 @@ import static android.os.PowerExemptionManager.REASON_SYSTEM_MODULE; import static android.os.PowerExemptionManager.REASON_SYSTEM_UID; import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE; import static android.os.PowerExemptionManager.REASON_UID_VISIBLE; +import static android.os.PowerExemptionManager.REASON_UNKNOWN; import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; import static android.os.PowerExemptionManager.getReasonCodeFromProcState; import static android.os.PowerExemptionManager.reasonCodeToString; @@ -7319,9 +7320,10 @@ public final class ActiveServices { r.mAllowWhileInUsePermissionInFgs = true; } + final @ReasonCode int allowWhileInUse; if (!r.mAllowWhileInUsePermissionInFgs || (r.mAllowStartForeground == REASON_DENIED)) { - final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked( + allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked( callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges, isBindService); if (!r.mAllowWhileInUsePermissionInFgs) { @@ -7332,6 +7334,24 @@ public final class ActiveServices { allowWhileInUse, callingPackage, callingPid, callingUid, intent, r, backgroundStartPrivileges, isBindService); } + } else { + allowWhileInUse = REASON_UNKNOWN; + } + // We want to allow scheduling user-initiated jobs when the app is running a + // foreground service that was started in the same conditions that allows for scheduling + // UI jobs. More explicitly, we want to allow scheduling UI jobs when the app is running + // an FGS that started when the app was in the TOP or a BAL-approved state. + // As of Android UDC, the conditions required for the while-in-use permissions + // are the same conditions that we want, so we piggyback on that logic. + // We use that as a shortcut if possible so we don't have to recheck all the conditions. + final boolean isFgs = r.isForeground || r.fgRequired; + if (isFgs) { + r.updateAllowUiJobScheduling(ActivityManagerService + .doesReasonCodeAllowSchedulingUserInitiatedJobs(allowWhileInUse) + || mAm.canScheduleUserInitiatedJobs( + callingUid, callingPid, callingPackage, true)); + } else { + r.updateAllowUiJobScheduling(false); } } @@ -7342,6 +7362,7 @@ public final class ActiveServices { r.mInfoTempFgsAllowListReason = null; r.mLoggedInfoAllowStartForeground = false; r.mLastSetFgsRestrictionTime = 0; + r.updateAllowUiJobScheduling(r.mAllowWhileInUsePermissionInFgs); } boolean canStartForegroundServiceLocked(int callingPid, int callingUid, String callingPackage) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 65c4d7581b4b..a3e582046b03 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -38,6 +38,8 @@ import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.StopUserOnSwitch; +import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN; +import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_UNFROZEN; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED; @@ -114,7 +116,6 @@ import static android.os.Process.setThreadScheduler; import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; import static android.provider.Settings.Global.DEBUG_APP; import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER; -import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS; import static android.view.Display.INVALID_DISPLAY; @@ -123,7 +124,6 @@ import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_RE import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST; @@ -372,7 +372,6 @@ import android.util.Pair; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -409,7 +408,6 @@ import com.android.internal.os.SomeArgs; import com.android.internal.os.TimeoutRecord; import com.android.internal.os.TransferPipe; import com.android.internal.os.Zygote; -import com.android.internal.os.anr.AnrLatencyTracker; import com.android.internal.policy.AttributeCache; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; @@ -488,14 +486,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -506,18 +500,13 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Supplier; public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock { @@ -555,8 +544,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final String SYSTEM_USER_HOME_NEEDED = "ro.system_user_home_needed"; - public static final String ANR_TRACE_DIR = "/data/anr"; - // Maximum number of receivers an app can register. private static final int MAX_RECEIVERS_ALLOWED_PER_APP = 1000; @@ -618,10 +605,6 @@ public class ActivityManagerService extends IActivityManager.Stub private static final int MAX_BUGREPORT_TITLE_SIZE = 100; private static final int MAX_BUGREPORT_DESCRIPTION_SIZE = 150; - private static final int NATIVE_DUMP_TIMEOUT_MS = - 2000 * Build.HW_TIMEOUT_MULTIPLIER; // 2 seconds; - private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes. - OomAdjuster mOomAdjuster; static final String EXTRA_TITLE = "android.intent.extra.TITLE"; @@ -3428,432 +3411,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - /** - * If a stack trace dump file is configured, dump process stack traces. - * @param firstPids of dalvik VM processes to dump stack traces for first - * @param lastPids of dalvik VM processes to dump stack traces for last - * @param nativePids optional list of native pids to dump stack crawls - * @param logExceptionCreatingFile optional writer to which we log errors creating the file - * @param auxiliaryTaskExecutor executor to execute auxiliary tasks on - * @param latencyTracker the latency tracker instance of the current ANR. - */ - public static File dumpStackTraces(ArrayList<Integer> firstPids, - ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids, - Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile, - @NonNull Executor auxiliaryTaskExecutor, AnrLatencyTracker latencyTracker) { - return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture, - logExceptionCreatingFile, null, null, null, auxiliaryTaskExecutor, latencyTracker); - } - - /** - * If a stack trace dump file is configured, dump process stack traces. - * @param firstPids of dalvik VM processes to dump stack traces for first - * @param lastPids of dalvik VM processes to dump stack traces for last - * @param nativePids optional list of native pids to dump stack crawls - * @param logExceptionCreatingFile optional writer to which we log errors creating the file - * @param subject optional line related to the error - * @param criticalEventSection optional lines containing recent critical events. - * @param auxiliaryTaskExecutor executor to execute auxiliary tasks on - * @param latencyTracker the latency tracker instance of the current ANR. - */ - public static File dumpStackTraces(ArrayList<Integer> firstPids, - ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids, - Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile, - String subject, String criticalEventSection, @NonNull Executor auxiliaryTaskExecutor, - AnrLatencyTracker latencyTracker) { - return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture, - logExceptionCreatingFile, null, subject, criticalEventSection, - auxiliaryTaskExecutor, latencyTracker); - } - - /** - * @param firstPidEndOffset Optional, when it's set, it receives the start/end offset - * of the very first pid to be dumped. - */ - /* package */ static File dumpStackTraces(ArrayList<Integer> firstPids, - ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids, - Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile, - AtomicLong firstPidEndOffset, String subject, String criticalEventSection, - @NonNull Executor auxiliaryTaskExecutor, AnrLatencyTracker latencyTracker) { - try { - - if (latencyTracker != null) { - latencyTracker.dumpStackTracesStarted(); - } - - Slog.i(TAG, "dumpStackTraces pids=" + lastPids); - - // Measure CPU usage as soon as we're called in order to get a realistic sampling - // of the top users at the time of the request. - Supplier<ArrayList<Integer>> extraPidsSupplier = processCpuTracker != null - ? () -> getExtraPids(processCpuTracker, lastPids, latencyTracker) : null; - Future<ArrayList<Integer>> extraPidsFuture = null; - if (extraPidsSupplier != null) { - extraPidsFuture = - CompletableFuture.supplyAsync(extraPidsSupplier, auxiliaryTaskExecutor); - } - - final File tracesDir = new File(ANR_TRACE_DIR); - - // NOTE: We should consider creating the file in native code atomically once we've - // gotten rid of the old scheme of dumping and lot of the code that deals with paths - // can be removed. - File tracesFile; - try { - tracesFile = createAnrDumpFile(tracesDir); - } catch (IOException e) { - Slog.w(TAG, "Exception creating ANR dump file:", e); - if (logExceptionCreatingFile != null) { - logExceptionCreatingFile.append( - "----- Exception creating ANR dump file -----\n"); - e.printStackTrace(new PrintWriter(logExceptionCreatingFile)); - } - if (latencyTracker != null) { - latencyTracker.anrSkippedDumpStackTraces(); - } - return null; - } - - if (subject != null || criticalEventSection != null) { - appendtoANRFile(tracesFile.getAbsolutePath(), - (subject != null ? "Subject: " + subject + "\n\n" : "") - + (criticalEventSection != null ? criticalEventSection : "")); - } - - long firstPidEndPos = dumpStackTraces( - tracesFile.getAbsolutePath(), firstPids, nativePidsFuture, - extraPidsFuture, latencyTracker); - if (firstPidEndOffset != null) { - firstPidEndOffset.set(firstPidEndPos); - } - // Each set of ANR traces is written to a separate file and dumpstate will process - // all such files and add them to a captured bug report if they're recent enough. - maybePruneOldTraces(tracesDir); - - return tracesFile; - } finally { - if (latencyTracker != null) { - latencyTracker.dumpStackTracesEnded(); - } - } - - } - - @GuardedBy("ActivityManagerService.class") - private static SimpleDateFormat sAnrFileDateFormat; - static final String ANR_FILE_PREFIX = "anr_"; - - private static ArrayList<Integer> getExtraPids(ProcessCpuTracker processCpuTracker, - SparseBooleanArray lastPids, AnrLatencyTracker latencyTracker) { - if (latencyTracker != null) { - latencyTracker.processCpuTrackerMethodsCalled(); - } - ArrayList<Integer> extraPids = new ArrayList<>(); - processCpuTracker.init(); - try { - Thread.sleep(200); - } catch (InterruptedException ignored) { - } - - processCpuTracker.update(); - - // We'll take the stack crawls of just the top apps using CPU. - final int workingStatsNumber = processCpuTracker.countWorkingStats(); - for (int i = 0; i < workingStatsNumber && extraPids.size() < 2; i++) { - ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i); - if (lastPids.indexOfKey(stats.pid) >= 0) { - if (DEBUG_ANR) { - Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid); - } - - extraPids.add(stats.pid); - } else { - Slog.i(TAG, - "Skipping next CPU consuming process, not a java proc: " - + stats.pid); - } - } - if (latencyTracker != null) { - latencyTracker.processCpuTrackerMethodsReturned(); - } - return extraPids; - } - - private static synchronized File createAnrDumpFile(File tracesDir) throws IOException { - if (sAnrFileDateFormat == null) { - sAnrFileDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS"); - } - - final String formattedDate = sAnrFileDateFormat.format(new Date()); - final File anrFile = new File(tracesDir, ANR_FILE_PREFIX + formattedDate); - - if (anrFile.createNewFile()) { - FileUtils.setPermissions(anrFile.getAbsolutePath(), 0600, -1, -1); // -rw------- - return anrFile; - } else { - throw new IOException("Unable to create ANR dump file: createNewFile failed"); - } - } - - /** - * Prune all trace files that are more than a day old. - * - * NOTE: It might make sense to move this functionality to tombstoned eventually, along with a - * shift away from anr_XX and tombstone_XX to a more descriptive name. We do it here for now - * since it's the system_server that creates trace files for most ANRs. - */ - private static void maybePruneOldTraces(File tracesDir) { - final File[] files = tracesDir.listFiles(); - if (files == null) return; - - final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64); - final long now = System.currentTimeMillis(); - try { - Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed()); - for (int i = 0; i < files.length; ++i) { - if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) { - if (!files[i].delete()) { - Slog.w(TAG, "Unable to prune stale trace file: " + files[i]); - } - } - } - } catch (IllegalArgumentException e) { - // The modification times changed while we were sorting. Bail... - // https://issuetracker.google.com/169836837 - Slog.w(TAG, "tombstone modification times changed while sorting; not pruning", e); - } - } - - /** - * Dump java traces for process {@code pid} to the specified file. If java trace dumping - * fails, a native backtrace is attempted. Note that the timeout {@code timeoutMs} only applies - * to the java section of the trace, a further {@code NATIVE_DUMP_TIMEOUT_MS} might be spent - * attempting to obtain native traces in the case of a failure. Returns the total time spent - * capturing traces. - */ - private static long dumpJavaTracesTombstoned(int pid, String fileName, long timeoutMs) { - final long timeStart = SystemClock.elapsedRealtime(); - int headerSize = writeUptimeStartHeaderForPid(pid, fileName); - boolean javaSuccess = Debug.dumpJavaBacktraceToFileTimeout(pid, fileName, - (int) (timeoutMs / 1000)); - if (javaSuccess) { - // Check that something is in the file, actually. Try-catch should not be necessary, - // but better safe than sorry. - try { - long size = new File(fileName).length(); - if ((size - headerSize) < JAVA_DUMP_MINIMUM_SIZE) { - Slog.w(TAG, "Successfully created Java ANR file is empty!"); - javaSuccess = false; - } - } catch (Exception e) { - Slog.w(TAG, "Unable to get ANR file size", e); - javaSuccess = false; - } - } - if (!javaSuccess) { - Slog.w(TAG, "Dumping Java threads failed, initiating native stack dump."); - if (!Debug.dumpNativeBacktraceToFileTimeout(pid, fileName, - (NATIVE_DUMP_TIMEOUT_MS / 1000))) { - Slog.w(TAG, "Native stack dump failed!"); - } - } - - return SystemClock.elapsedRealtime() - timeStart; - } - - private static int appendtoANRFile(String fileName, String text) { - try (FileOutputStream fos = new FileOutputStream(fileName, true)) { - byte[] header = text.getBytes(StandardCharsets.UTF_8); - fos.write(header); - return header.length; - } catch (IOException e) { - Slog.w(TAG, "Exception writing to ANR dump file:", e); - return 0; - } - } - - /* - * Writes a header containing the process id and the current system uptime. - */ - private static int writeUptimeStartHeaderForPid(int pid, String fileName) { - return appendtoANRFile(fileName, "----- dumping pid: " + pid + " at " - + SystemClock.uptimeMillis() + "\n"); - } - - - /** - * @return The end offset of the trace of the very first PID - */ - public static long dumpStackTraces(String tracesFile, - ArrayList<Integer> firstPids, Future<ArrayList<Integer>> nativePidsFuture, - Future<ArrayList<Integer>> extraPidsFuture, AnrLatencyTracker latencyTracker) { - - Slog.i(TAG, "Dumping to " + tracesFile); - - // We don't need any sort of inotify based monitoring when we're dumping traces via - // tombstoned. Data is piped to an "intercept" FD installed in tombstoned so we're in full - // control of all writes to the file in question. - - // We must complete all stack dumps within 20 seconds. - long remainingTime = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; - - // As applications are usually interested with the ANR stack traces, but we can't share with - // them the stack traces other than their own stacks. So after the very first PID is - // dumped, remember the current file size. - long firstPidEnd = -1; - - // First collect all of the stacks of the most important pids. - if (firstPids != null) { - if (latencyTracker != null) { - latencyTracker.dumpingFirstPidsStarted(); - } - - int num = firstPids.size(); - for (int i = 0; i < num; i++) { - final int pid = firstPids.get(i); - // We don't copy ANR traces from the system_server intentionally. - final boolean firstPid = i == 0 && MY_PID != pid; - if (latencyTracker != null) { - latencyTracker.dumpingPidStarted(pid); - } - - Slog.i(TAG, "Collecting stacks for pid " + pid); - final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, - remainingTime); - if (latencyTracker != null) { - latencyTracker.dumpingPidEnded(); - } - - remainingTime -= timeTaken; - if (remainingTime <= 0) { - Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + pid - + "); deadline exceeded."); - return firstPidEnd; - } - - if (firstPid) { - firstPidEnd = new File(tracesFile).length(); - // Full latency dump - if (latencyTracker != null) { - appendtoANRFile(tracesFile, - latencyTracker.dumpAsCommaSeparatedArrayWithHeader()); - } - } - if (DEBUG_ANR) { - Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms"); - } - } - if (latencyTracker != null) { - latencyTracker.dumpingFirstPidsEnded(); - } - } - - // Next collect the stacks of the native pids - ArrayList<Integer> nativePids = collectPids(nativePidsFuture, "native pids"); - - Slog.i(TAG, "dumpStackTraces nativepids=" + nativePids); - - if (nativePids != null) { - if (latencyTracker != null) { - latencyTracker.dumpingNativePidsStarted(); - } - for (int pid : nativePids) { - Slog.i(TAG, "Collecting stacks for native pid " + pid); - final long nativeDumpTimeoutMs = Math.min(NATIVE_DUMP_TIMEOUT_MS, remainingTime); - - if (latencyTracker != null) { - latencyTracker.dumpingPidStarted(pid); - } - final long start = SystemClock.elapsedRealtime(); - Debug.dumpNativeBacktraceToFileTimeout( - pid, tracesFile, (int) (nativeDumpTimeoutMs / 1000)); - final long timeTaken = SystemClock.elapsedRealtime() - start; - if (latencyTracker != null) { - latencyTracker.dumpingPidEnded(); - } - remainingTime -= timeTaken; - if (remainingTime <= 0) { - Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid + - "); deadline exceeded."); - return firstPidEnd; - } - - if (DEBUG_ANR) { - Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms"); - } - } - if (latencyTracker != null) { - latencyTracker.dumpingNativePidsEnded(); - } - } - - // Lastly, dump stacks for all extra PIDs from the CPU tracker. - ArrayList<Integer> extraPids = collectPids(extraPidsFuture, "extra pids"); - - if (extraPidsFuture != null) { - try { - extraPids = extraPidsFuture.get(); - } catch (ExecutionException e) { - Slog.w(TAG, "Failed to collect extra pids", e.getCause()); - } catch (InterruptedException e) { - Slog.w(TAG, "Interrupted while collecting extra pids", e); - } - } - Slog.i(TAG, "dumpStackTraces extraPids=" + extraPids); - - if (extraPids != null) { - if (latencyTracker != null) { - latencyTracker.dumpingExtraPidsStarted(); - } - for (int pid : extraPids) { - Slog.i(TAG, "Collecting stacks for extra pid " + pid); - if (latencyTracker != null) { - latencyTracker.dumpingPidStarted(pid); - } - final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime); - if (latencyTracker != null) { - latencyTracker.dumpingPidEnded(); - } - remainingTime -= timeTaken; - if (remainingTime <= 0) { - Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid + - "); deadline exceeded."); - return firstPidEnd; - } - - if (DEBUG_ANR) { - Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms"); - } - } - if (latencyTracker != null) { - latencyTracker.dumpingExtraPidsEnded(); - } - } - // Append the dumping footer with the current uptime - appendtoANRFile(tracesFile, "----- dumping ended at " + SystemClock.uptimeMillis() + "\n"); - Slog.i(TAG, "Done dumping"); - - return firstPidEnd; - } - - private static ArrayList<Integer> collectPids(Future<ArrayList<Integer>> pidsFuture, - String logName) { - - ArrayList<Integer> pids = null; - - if (pidsFuture == null) { - return pids; - } - try { - pids = pidsFuture.get(); - } catch (ExecutionException e) { - Slog.w(TAG, "Failed to collect " + logName, e.getCause()); - } catch (InterruptedException e) { - Slog.w(TAG, "Interrupted while collecting " + logName , e); - } - return pids; - } - @Override public boolean clearApplicationUserData(final String packageName, boolean keepState, final IPackageDataObserver observer, int userId) { @@ -6563,7 +6120,7 @@ public class ActivityManagerService extends IActivityManager.Stub * This is a shortcut and <b>DOES NOT</b> include all reasons. * Use {@link #canScheduleUserInitiatedJobs(int, int, String)} to cover all cases. */ - private boolean doesReasonCodeAllowSchedulingUserInitiatedJobs(int reasonCode) { + static boolean doesReasonCodeAllowSchedulingUserInitiatedJobs(int reasonCode) { switch (reasonCode) { case REASON_PROC_STATE_PERSISTENT: case REASON_PROC_STATE_PERSISTENT_UI: @@ -6621,6 +6178,16 @@ public class ActivityManagerService extends IActivityManager.Stub } } + final ProcessServiceRecord psr = pr.mServices; + if (psr != null && psr.hasForegroundServices()) { + for (int s = psr.numberOfExecutingServices() - 1; s >= 0; --s) { + final ServiceRecord sr = psr.getExecutingServiceAt(s); + if (sr.isForeground && sr.mAllowUiJobScheduling) { + return true; + } + } + } + return false; } @@ -6630,6 +6197,11 @@ public class ActivityManagerService extends IActivityManager.Stub */ // TODO(262260570): log allow reason to an atom private boolean canScheduleUserInitiatedJobs(int uid, int pid, String pkgName) { + return canScheduleUserInitiatedJobs(uid, pid, pkgName, false); + } + + boolean canScheduleUserInitiatedJobs(int uid, int pid, String pkgName, + boolean skipWhileInUseCheck) { synchronized (this) { final ProcessRecord processRecord; synchronized (mPidsSelfLocked) { @@ -6659,7 +6231,7 @@ public class ActivityManagerService extends IActivityManager.Stub // As of Android UDC, the conditions required to grant a while-in-use permission // covers the majority of those cases, and so we piggyback on that logic as the base. // Missing cases are added after. - if (mServices.canAllowWhileInUsePermissionInFgsLocked( + if (!skipWhileInUseCheck && mServices.canAllowWhileInUsePermissionInFgsLocked( pid, uid, pkgName, processRecord, backgroundStartPrivileges)) { return true; } @@ -7412,8 +6984,9 @@ public class ActivityManagerService extends IActivityManager.Stub mActivityTaskManager.onScreenAwakeChanged(isAwake); mOomAdjProfiler.onWakefulnessChanged(wakefulness); mOomAdjuster.onWakefulnessChanged(wakefulness); + + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } - updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -7930,9 +7503,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void registerUidFrozenStateChangedCallback( @NonNull IUidFrozenStateChangedCallback callback) { + Preconditions.checkNotNull(callback, "callback cannot be null"); enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS, "registerUidFrozenStateChangedCallback()"); - Preconditions.checkNotNull(callback, "callback cannot be null"); synchronized (mUidFrozenStateChangedCallbackList) { final boolean registered = mUidFrozenStateChangedCallbackList.register(callback); if (!registered) { @@ -7950,15 +7523,48 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void unregisterUidFrozenStateChangedCallback( @NonNull IUidFrozenStateChangedCallback callback) { + Preconditions.checkNotNull(callback, "callback cannot be null"); enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS, "unregisterUidFrozenStateChangedCallback()"); - Preconditions.checkNotNull(callback, "callback cannot be null"); synchronized (mUidFrozenStateChangedCallbackList) { mUidFrozenStateChangedCallbackList.unregister(callback); } } /** + * Query the frozen state of a list of UIDs. + * + * @param uids the array of UIDs which the client would like to know the frozen state of. + * @return An array containing the frozen state for each requested UID, by index. Will be set + * to {@link UidFrozenStateChangedCallback#UID_FROZEN_STATE_FROZEN} + * if the UID is frozen. If the UID is not frozen or not found, + * {@link UidFrozenStateChangedCallback#UID_FROZEN_STATE_UNFROZEN} + * will be set. + * + * @hide + */ + @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS) + @Override + public @NonNull int[] getUidFrozenState(@NonNull int[] uids) { + Preconditions.checkNotNull(uids, "uid array cannot be null"); + enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS, + "getUidFrozenState()"); + + final int[] frozenStates = new int[uids.length]; + synchronized (mProcLock) { + for (int i = 0; i < uids.length; i++) { + final UidRecord uidRec = mProcessList.mActiveUids.get(uids[i]); + if (uidRec != null && uidRec.areAllProcessesFrozen()) { + frozenStates[i] = UID_FROZEN_STATE_FROZEN; + } else { + frozenStates[i] = UID_FROZEN_STATE_UNFROZEN; + } + } + } + return frozenStates; + } + + /** * Notify the system that a UID has been frozen or unfrozen. * * @param uids The Uid(s) in question @@ -9040,13 +8646,16 @@ public class ActivityManagerService extends IActivityManager.Stub } } + boolean recoverable = eventType.equals("native_recoverable_crash"); + EventLogTags.writeAmCrash(Binder.getCallingPid(), UserHandle.getUserId(Binder.getCallingUid()), processName, r == null ? -1 : r.info.flags, crashInfo.exceptionClassName, crashInfo.exceptionMessage, crashInfo.throwFileName, - crashInfo.throwLineNumber); + crashInfo.throwLineNumber, + recoverable ? 1 : 0); int processClassEnum = processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER : (r != null) ? r.getProcessClassEnum() @@ -9114,7 +8723,13 @@ public class ActivityManagerService extends IActivityManager.Stub eventType, r, processName, null, null, null, null, null, null, crashInfo, new Float(loadingProgress), incrementalMetrics, null); - mAppErrors.crashApplication(r, crashInfo); + // For GWP-ASan recoverable crashes, don't make the app crash (the whole point of + // 'recoverable' is that the app doesn't crash). Normally, for nonrecoreable native crashes, + // debuggerd will terminate the process, but there's a backup where ActivityManager will + // also kill it. Avoid that. + if (!recoverable) { + mAppErrors.crashApplication(r, crashInfo); + } } public void handleApplicationStrictModeViolation( @@ -19175,7 +18790,7 @@ public class ActivityManagerService extends IActivityManager.Stub final IApplicationThread thread = app.getOnewayThread(); if (thread != null) { mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app, - OomAdjuster.OOM_ADJ_REASON_NONE); + CachedAppOptimizer.UNFREEZE_REASON_PING); pingCount.incrementAndGet(); try { thread.schedulePing(pongCallback); diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index 1ba326680fc2..44436369fb31 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -1153,7 +1153,7 @@ public final class AppExitInfoTracker { final ArraySet<String> allFiles = new ArraySet(); final File[] files = mProcExitStoreDir.listFiles((f) -> { final String name = f.getName(); - boolean trace = name.startsWith(ActivityManagerService.ANR_FILE_PREFIX) + boolean trace = name.startsWith(StackTracesDumpHelper.ANR_FILE_PREFIX) && name.endsWith(APP_TRACE_FILE_SUFFIX); if (trace) { allFiles.add(name); diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index dd6598f8e521..ccd739006713 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -45,7 +45,6 @@ import static com.android.server.am.ActivityManagerService.appendMemInfo; import static com.android.server.am.ActivityManagerService.getKsmInfo; import static com.android.server.am.ActivityManagerService.stringifyKBSize; import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING; -import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_NONE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import static com.android.server.wm.ActivityTaskManagerService.DUMP_ACTIVITIES_CMD; @@ -1119,7 +1118,7 @@ public class AppProfiler { Slog.v(TAG_OOM_ADJ, msg + app.processName + " to " + level); } mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app, - OOM_ADJ_REASON_NONE); + CachedAppOptimizer.UNFREEZE_REASON_TRIM_MEMORY); thread.scheduleTrimMemory(level); } catch (RemoteException e) { } diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index a92723ee7036..749427730ca0 100644 --- a/services/core/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.annotation.Nullable; import android.content.IntentFilter; import android.util.PrintWriterPrinter; import android.util.Printer; @@ -55,6 +56,16 @@ final class BroadcastFilter extends IntentFilter { exported = _exported; } + public @Nullable String getReceiverClassName() { + if (receiverId != null) { + final int index = receiverId.lastIndexOf('@'); + if (index > 0) { + return receiverId.substring(0, index); + } + } + return null; + } + @NeverCompile public void dumpDebug(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 0cdd4e9041e9..056e17a5ef3c 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -393,6 +393,10 @@ class BroadcastProcessQueue { setProcessInstrumented(false); setProcessPersistent(false); } + + // Since we may have just changed our PID, invalidate cached strings + mCachedToString = null; + mCachedToShortString = null; } /** @@ -1128,16 +1132,16 @@ class BroadcastProcessQueue { @Override public String toString() { if (mCachedToString == null) { - mCachedToString = "BroadcastProcessQueue{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + processName + "/" + UserHandle.formatUid(uid) + "}"; + mCachedToString = "BroadcastProcessQueue{" + toShortString() + "}"; } return mCachedToString; } public String toShortString() { if (mCachedToShortString == null) { - mCachedToShortString = processName + "/" + UserHandle.formatUid(uid); + mCachedToShortString = Integer.toHexString(System.identityHashCode(this)) + + " " + ((app != null) ? app.getPid() : "?") + ":" + processName + "/" + + UserHandle.formatUid(uid); } return mCachedToShortString; } diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java index fcddff0e5ebc..4b8dc99c67d9 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java @@ -37,7 +37,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_L import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; -import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER; import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_START_RECEIVER; import android.annotation.NonNull; @@ -837,7 +836,7 @@ public class BroadcastQueueImpl extends BroadcastQueue { } } else if (filter.receiverList.app != null) { mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app, - OOM_ADJ_REASON_START_RECEIVER); + CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER); } try { @@ -1131,7 +1130,8 @@ public class BroadcastQueueImpl extends BroadcastQueue { if (sendResult) { if (r.callerApp != null) { mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily( - r.callerApp, OOM_ADJ_REASON_FINISH_RECEIVER); + r.callerApp, + CachedAppOptimizer.UNFREEZE_REASON_FINISH_RECEIVER); } try { if (DEBUG_BROADCAST) { diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 1f0b1628aa22..5010ec03285f 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -32,11 +32,11 @@ import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList import static com.android.server.am.BroadcastProcessQueue.reasonToString; import static com.android.server.am.BroadcastProcessQueue.removeFromRunnableList; import static com.android.server.am.BroadcastRecord.deliveryStateToString; +import static com.android.server.am.BroadcastRecord.getReceiverClassName; import static com.android.server.am.BroadcastRecord.getReceiverPackageName; import static com.android.server.am.BroadcastRecord.getReceiverProcessName; import static com.android.server.am.BroadcastRecord.getReceiverUid; import static com.android.server.am.BroadcastRecord.isDeliveryStateTerminal; -import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER; import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_START_RECEIVER; import android.annotation.NonNull; @@ -928,7 +928,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { final IApplicationThread thread = (app != null) ? app.getOnewayThread() : null; if (thread != null) { mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily( - app, OOM_ADJ_REASON_FINISH_RECEIVER); + app, CachedAppOptimizer.UNFREEZE_REASON_FINISH_RECEIVER); if (r.shareIdentity && app.uid != r.callingUid) { mService.mPackageManagerInt.grantImplicitAccess(r.userId, r.intent, UserHandle.getAppId(app.uid), r.callingUid, true); @@ -1040,7 +1040,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) { r.anrCount++; if (app != null && !app.isDebugging()) { - mService.appNotResponding(queue.app, TimeoutRecord.forBroadcastReceiver(r.intent)); + final String packageName = getReceiverPackageName(receiver); + final String className = getReceiverClassName(receiver); + mService.appNotResponding(queue.app, + TimeoutRecord.forBroadcastReceiver(r.intent, packageName, className)); } } else { mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue); @@ -1511,7 +1514,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(queue.app, - OOM_ADJ_REASON_START_RECEIVER); + CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER); if (queue.runningOomAdjusted) { queue.app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 6bd3c7953e01..c368290386a0 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -832,6 +832,14 @@ final class BroadcastRecord extends Binder { } } + static @Nullable String getReceiverClassName(@NonNull Object receiver) { + if (receiver instanceof BroadcastFilter) { + return ((BroadcastFilter) receiver).getReceiverClassName(); + } else /* if (receiver instanceof ResolveInfo) */ { + return ((ResolveInfo) receiver).activityInfo.name; + } + } + static int getReceiverPriority(@NonNull Object receiver) { if (receiver instanceof BroadcastFilter) { return ((BroadcastFilter) receiver).getPriority(); @@ -999,23 +1007,50 @@ final class BroadcastRecord extends Binder { private static boolean matchesDeliveryGroup(@NonNull BroadcastRecord newRecord, @NonNull BroadcastRecord oldRecord) { - final String newMatchingKey = getDeliveryGroupMatchingKey(newRecord); - final String oldMatchingKey = getDeliveryGroupMatchingKey(oldRecord); final IntentFilter newMatchingFilter = getDeliveryGroupMatchingFilter(newRecord); // If neither delivery group key nor matching filter is specified, then use // Intent.filterEquals() to identify the delivery group. - if (newMatchingKey == null && oldMatchingKey == null && newMatchingFilter == null) { + if (isMatchingKeyNull(newRecord) && isMatchingKeyNull(oldRecord) + && newMatchingFilter == null) { return newRecord.intent.filterEquals(oldRecord.intent); } if (newMatchingFilter != null && !newMatchingFilter.asPredicate().test(oldRecord.intent)) { return false; } - return Objects.equals(newMatchingKey, oldMatchingKey); + return areMatchingKeysEqual(newRecord, oldRecord); + } + + private static boolean isMatchingKeyNull(@NonNull BroadcastRecord record) { + final String namespace = getDeliveryGroupMatchingNamespaceFragment(record); + final String key = getDeliveryGroupMatchingKeyFragment(record); + // If either namespace or key part is null, then treat the entire matching key as null. + return namespace == null || key == null; + } + + private static boolean areMatchingKeysEqual(@NonNull BroadcastRecord newRecord, + @NonNull BroadcastRecord oldRecord) { + final String newNamespaceFragment = getDeliveryGroupMatchingNamespaceFragment(newRecord); + final String oldNamespaceFragment = getDeliveryGroupMatchingNamespaceFragment(oldRecord); + if (!Objects.equals(newNamespaceFragment, oldNamespaceFragment)) { + return false; + } + + final String newKeyFragment = getDeliveryGroupMatchingKeyFragment(newRecord); + final String oldKeyFragment = getDeliveryGroupMatchingKeyFragment(oldRecord); + return Objects.equals(newKeyFragment, oldKeyFragment); + } + + @Nullable + private static String getDeliveryGroupMatchingNamespaceFragment( + @NonNull BroadcastRecord record) { + return record.options == null + ? null : record.options.getDeliveryGroupMatchingNamespaceFragment(); } @Nullable - private static String getDeliveryGroupMatchingKey(@NonNull BroadcastRecord record) { - return record.options == null ? null : record.options.getDeliveryGroupMatchingKey(); + private static String getDeliveryGroupMatchingKeyFragment(@NonNull BroadcastRecord record) { + return record.options == null + ? null : record.options.getDeliveryGroupMatchingKeyFragment(); } @Nullable @@ -1041,9 +1076,7 @@ final class BroadcastRecord extends Binder { if (label == null) { label = intent.toString(); } - mCachedToString = "BroadcastRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " u" + userId + " " + label + "}"; + mCachedToString = "BroadcastRecord{" + toShortString() + "}"; } return mCachedToString; } @@ -1055,7 +1088,7 @@ final class BroadcastRecord extends Binder { label = intent.toString(); } mCachedToShortString = Integer.toHexString(System.identityHashCode(this)) - + ":" + label + "/u" + userId; + + " " + label + "/u" + userId; } return mCachedToShortString; } diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index b293bcf0e17d..6c9f602bbc94 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -23,6 +23,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FREEZER; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import android.annotation.IntDef; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ApplicationExitInfo; @@ -54,6 +55,8 @@ import com.android.server.ServiceThread; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumMap; @@ -94,6 +97,70 @@ public final class CachedAppOptimizer { @VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG = "freeze_exempt_inst_pkg"; + + static final int UNFREEZE_REASON_NONE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE; + static final int UNFREEZE_REASON_ACTIVITY = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_ACTIVITY; + static final int UNFREEZE_REASON_FINISH_RECEIVER = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FINISH_RECEIVER; + static final int UNFREEZE_REASON_START_RECEIVER = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_START_RECEIVER; + static final int UNFREEZE_REASON_BIND_SERVICE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_BIND_SERVICE; + static final int UNFREEZE_REASON_UNBIND_SERVICE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_UNBIND_SERVICE; + static final int UNFREEZE_REASON_START_SERVICE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_START_SERVICE; + static final int UNFREEZE_REASON_GET_PROVIDER = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_GET_PROVIDER; + static final int UNFREEZE_REASON_REMOVE_PROVIDER = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_REMOVE_PROVIDER; + static final int UNFREEZE_REASON_UI_VISIBILITY = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_UI_VISIBILITY; + static final int UNFREEZE_REASON_ALLOWLIST = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_ALLOWLIST; + static final int UNFREEZE_REASON_PROCESS_BEGIN = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_PROCESS_BEGIN; + static final int UNFREEZE_REASON_PROCESS_END = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_PROCESS_END; + static final int UNFREEZE_REASON_TRIM_MEMORY = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_TRIM_MEMORY; + static final int UNFREEZE_REASON_PING = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_PING; + static final int UNFREEZE_REASON_FILE_LOCKS = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FILE_LOCKS; + static final int UNFREEZE_REASON_FILE_LOCK_CHECK_FAILURE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FILE_LOCK_CHECK_FAILURE; + static final int UNFREEZE_REASON_BINDER_TXNS = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_BINDER_TXNS; + static final int UNFREEZE_REASON_FEATURE_FLAGS = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FEATURE_FLAGS; + + @IntDef(prefix = {"UNFREEZE_REASON_"}, value = { + UNFREEZE_REASON_NONE, + UNFREEZE_REASON_ACTIVITY, + UNFREEZE_REASON_FINISH_RECEIVER, + UNFREEZE_REASON_START_RECEIVER, + UNFREEZE_REASON_BIND_SERVICE, + UNFREEZE_REASON_UNBIND_SERVICE, + UNFREEZE_REASON_START_SERVICE, + UNFREEZE_REASON_GET_PROVIDER, + UNFREEZE_REASON_REMOVE_PROVIDER, + UNFREEZE_REASON_UI_VISIBILITY, + UNFREEZE_REASON_ALLOWLIST, + UNFREEZE_REASON_PROCESS_BEGIN, + UNFREEZE_REASON_PROCESS_END, + UNFREEZE_REASON_TRIM_MEMORY, + UNFREEZE_REASON_PING, + UNFREEZE_REASON_FILE_LOCKS, + UNFREEZE_REASON_FILE_LOCK_CHECK_FAILURE, + UNFREEZE_REASON_BINDER_TXNS, + UNFREEZE_REASON_FEATURE_FLAGS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UnfreezeReason {} + // RSS Indices private static final int RSS_TOTAL_INDEX = 0; private static final int RSS_FILE_INDEX = 1; @@ -888,7 +955,7 @@ public final class CachedAppOptimizer { } if (!enable && opt.isFrozen()) { - unfreezeAppLSP(process, OomAdjuster.OOM_ADJ_REASON_NONE); + unfreezeAppLSP(process, UNFREEZE_REASON_FEATURE_FLAGS); // Set freezerOverride *after* calling unfreezeAppLSP (it resets the flag) opt.setFreezerOverride(true); @@ -1194,7 +1261,7 @@ public final class CachedAppOptimizer { // This will ensure app will be out of the freezer for at least mFreezerDebounceTimeout. @GuardedBy("mAm") - void unfreezeTemporarily(ProcessRecord app, @OomAdjuster.OomAdjReason int reason) { + void unfreezeTemporarily(ProcessRecord app, @UnfreezeReason int reason) { if (mUseFreezer) { synchronized (mProcLock) { if (app.mOptRecord.isFrozen() || app.mOptRecord.isPendingFreeze()) { @@ -1224,7 +1291,7 @@ public final class CachedAppOptimizer { } @GuardedBy({"mAm", "mProcLock", "mFreezerLock"}) - void unfreezeAppInternalLSP(ProcessRecord app, @OomAdjuster.OomAdjReason int reason) { + void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason) { final int pid = app.getPid(); final ProcessCachedOptimizerRecord opt = app.mOptRecord; if (opt.isPendingFreeze()) { @@ -1318,7 +1385,7 @@ public final class CachedAppOptimizer { } @GuardedBy({"mAm", "mProcLock"}) - void unfreezeAppLSP(ProcessRecord app, @OomAdjuster.OomAdjReason int reason) { + void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) { synchronized (mFreezerLock) { unfreezeAppInternalLSP(app, reason); } @@ -1950,7 +2017,7 @@ public final class CachedAppOptimizer { + name + "(" + pid + "): " + e); synchronized (mAm) { synchronized (mProcLock) { - unfreezeAppLSP(proc, OomAdjuster.OOM_ADJ_REASON_NONE); + unfreezeAppLSP(proc, UNFREEZE_REASON_FILE_LOCK_CHECK_FAILURE); } } } @@ -1975,10 +2042,11 @@ public final class CachedAppOptimizer { } @GuardedBy({"mAm", "mProcLock"}) - private void rescheduleFreeze(final ProcessRecord proc, final String reason) { + private void rescheduleFreeze(final ProcessRecord proc, final String reason, + @UnfreezeReason int reasonCode) { Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid() + " " + proc.processName + " (" + reason + ")"); - unfreezeAppLSP(proc, OomAdjuster.OOM_ADJ_REASON_NONE); + unfreezeAppLSP(proc, reasonCode); freezeAppAsyncLSP(proc); } @@ -2024,7 +2092,7 @@ public final class CachedAppOptimizer { // transactions that might be pending. try { if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) { - rescheduleFreeze(proc, "outstanding txns"); + rescheduleFreeze(proc, "outstanding txns", UNFREEZE_REASON_BINDER_TXNS); return; } } catch (RuntimeException e) { @@ -2076,7 +2144,8 @@ public final class CachedAppOptimizer { pid, name, unfrozenDuration, - FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE); + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE, + UNFREEZE_REASON_NONE); } try { @@ -2085,7 +2154,7 @@ public final class CachedAppOptimizer { if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) { synchronized (mProcLock) { - rescheduleFreeze(proc, "new pending txns"); + rescheduleFreeze(proc, "new pending txns", UNFREEZE_REASON_BINDER_TXNS); } return; } @@ -2102,7 +2171,7 @@ public final class CachedAppOptimizer { } private void reportUnfreeze(int pid, int frozenDuration, String processName, - @OomAdjuster.OomAdjReason int reason) { + @UnfreezeReason int reason) { EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName); @@ -2114,38 +2183,8 @@ public final class CachedAppOptimizer { pid, processName, frozenDuration, - getUnfreezeReasonCode(reason)); - } - } - - private int getUnfreezeReasonCode(@OomAdjuster.OomAdjReason int oomAdjReason) { - switch (oomAdjReason) { - case OomAdjuster.OOM_ADJ_REASON_ACTIVITY: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__ACTIVITY; - case OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__FINISH_RECEIVER; - case OomAdjuster.OOM_ADJ_REASON_START_RECEIVER: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__START_RECEIVER; - case OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__BIND_SERVICE; - case OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__UNBIND_SERVICE; - case OomAdjuster.OOM_ADJ_REASON_START_SERVICE: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__START_SERVICE; - case OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__GET_PROVIDER; - case OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__REMOVE_PROVIDER; - case OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__UI_VISIBILITY; - case OomAdjuster.OOM_ADJ_REASON_ALLOWLIST: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__ALLOWLIST; - case OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__PROCESS_BEGIN; - case OomAdjuster.OOM_ADJ_REASON_PROCESS_END: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__PROCESS_END; - default: - return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE; + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE, // deprecated + reason); } } @@ -2171,7 +2210,7 @@ public final class CachedAppOptimizer { Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks " + pr.processName + " (" + blocked + ")"); // Found at least one blocked non-cached process - unfreezeAppLSP(app, OomAdjuster.OOM_ADJ_REASON_NONE); + unfreezeAppLSP(app, UNFREEZE_REASON_FILE_LOCKS); break; } } @@ -2207,4 +2246,35 @@ public final class CachedAppOptimizer { mPidCompacting = -1; } } + + static int getUnfreezeReasonCodeFromOomAdjReason(@OomAdjuster.OomAdjReason int oomAdjReason) { + switch (oomAdjReason) { + case OomAdjuster.OOM_ADJ_REASON_ACTIVITY: + return UNFREEZE_REASON_ACTIVITY; + case OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER: + return UNFREEZE_REASON_FINISH_RECEIVER; + case OomAdjuster.OOM_ADJ_REASON_START_RECEIVER: + return UNFREEZE_REASON_START_RECEIVER; + case OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE: + return UNFREEZE_REASON_BIND_SERVICE; + case OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE: + return UNFREEZE_REASON_UNBIND_SERVICE; + case OomAdjuster.OOM_ADJ_REASON_START_SERVICE: + return UNFREEZE_REASON_START_SERVICE; + case OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER: + return UNFREEZE_REASON_GET_PROVIDER; + case OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER: + return UNFREEZE_REASON_REMOVE_PROVIDER; + case OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY: + return UNFREEZE_REASON_UI_VISIBILITY; + case OomAdjuster.OOM_ADJ_REASON_ALLOWLIST: + return UNFREEZE_REASON_ALLOWLIST; + case OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN: + return UNFREEZE_REASON_PROCESS_BEGIN; + case OomAdjuster.OOM_ADJ_REASON_PROCESS_END: + return UNFREEZE_REASON_PROCESS_END; + default: + return UNFREEZE_REASON_NONE; + } + } } diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 50841ae4488c..81b242155bac 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -53,7 +53,7 @@ option java_package com.android.server.am 30037 am_process_start_timeout (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3) # Unhandled exception -30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5) +30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5),(Recoverable|1|5) # Log.wtf() called 30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3) diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java index 94eb07611037..cd119e7e3fbc 100644 --- a/services/core/java/com/android/server/am/NativeCrashListener.java +++ b/services/core/java/com/android/server/am/NativeCrashListener.java @@ -64,12 +64,15 @@ final class NativeCrashListener extends Thread { class NativeCrashReporter extends Thread { ProcessRecord mApp; int mSignal; + boolean mGwpAsanRecoverableCrash; String mCrashReport; - NativeCrashReporter(ProcessRecord app, int signal, String report) { + NativeCrashReporter(ProcessRecord app, int signal, boolean gwpAsanRecoverableCrash, + String report) { super("NativeCrashReport"); mApp = app; mSignal = signal; + mGwpAsanRecoverableCrash = gwpAsanRecoverableCrash; mCrashReport = report; } @@ -85,7 +88,9 @@ final class NativeCrashListener extends Thread { ci.stackTrace = mCrashReport; if (DEBUG) Slog.v(TAG, "Calling handleApplicationCrash()"); - mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci); + mAm.handleApplicationCrashInner( + mGwpAsanRecoverableCrash ? "native_recoverable_crash" : "native_crash", + mApp, mApp.processName, ci); if (DEBUG) Slog.v(TAG, "<-- handleApplicationCrash() returned"); } catch (Exception e) { Slog.e(TAG, "Unable to report native crash", e); @@ -207,9 +212,14 @@ final class NativeCrashListener extends Thread { // permits crash_dump to connect to it. This allows us to trust the // received values. - // first, the pid and signal number - int headerBytes = readExactly(fd, buf, 0, 8); - if (headerBytes != 8) { + // Activity Manager protocol: + // - 32-bit network-byte-order: pid + // - 32-bit network-byte-order: signal number + // - byte: gwpAsanRecoverableCrash + // - bytes: raw text of the dump + // - null terminator + int headerBytes = readExactly(fd, buf, 0, 9); + if (headerBytes != 9) { // protocol failure; give up Slog.e(TAG, "Unable to read from debuggerd"); return; @@ -217,69 +227,76 @@ final class NativeCrashListener extends Thread { int pid = unpackInt(buf, 0); int signal = unpackInt(buf, 4); + boolean gwpAsanRecoverableCrash = buf[8] != 0; if (DEBUG) { - Slog.v(TAG, "Read pid=" + pid + " signal=" + signal); + Slog.v(TAG, "Read pid=" + pid + " signal=" + signal + + " recoverable=" + gwpAsanRecoverableCrash); + } + if (pid < 0) { + Slog.e(TAG, "Bogus pid!"); + return; } // now the text of the dump - if (pid > 0) { - final ProcessRecord pr; - synchronized (mAm.mPidsSelfLocked) { - pr = mAm.mPidsSelfLocked.get(pid); + final ProcessRecord pr; + synchronized (mAm.mPidsSelfLocked) { + pr = mAm.mPidsSelfLocked.get(pid); + } + if (pr == null) { + Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid); + return; + } + + // Don't attempt crash reporting for persistent apps + if (pr.isPersistent()) { + if (DEBUG) { + Slog.v(TAG, "Skipping report for persistent app " + pr); } - if (pr != null) { - // Don't attempt crash reporting for persistent apps - if (pr.isPersistent()) { - if (DEBUG) { - Slog.v(TAG, "Skipping report for persistent app " + pr); - } - return; - } + return; + } - int bytes; - do { - // get some data - bytes = Os.read(fd, buf, 0, buf.length); - if (bytes > 0) { - if (MORE_DEBUG) { - String s = new String(buf, 0, bytes, "UTF-8"); - Slog.v(TAG, "READ=" + bytes + "> " + s); - } - // did we just get the EOD null byte? - if (buf[bytes-1] == 0) { - os.write(buf, 0, bytes-1); // exclude the EOD token - break; - } - // no EOD, so collect it and read more - os.write(buf, 0, bytes); - } - } while (bytes > 0); - - // Okay, we've got the report. - if (DEBUG) Slog.v(TAG, "processing"); - - // Mark the process record as being a native crash so that the - // cleanup mechanism knows we're still submitting the report - // even though the process will vanish as soon as we let - // debuggerd proceed. - synchronized (mAm) { - synchronized (mAm.mProcLock) { - pr.mErrorState.setCrashing(true); - pr.mErrorState.setForceCrashReport(true); - } + int bytes; + do { + // get some data + bytes = Os.read(fd, buf, 0, buf.length); + if (bytes > 0) { + if (MORE_DEBUG) { + String s = new String(buf, 0, bytes, "UTF-8"); + Slog.v(TAG, "READ=" + bytes + "> " + s); + } + // did we just get the EOD null byte? + if (buf[bytes - 1] == 0) { + os.write(buf, 0, bytes - 1); // exclude the EOD token + break; + } + // no EOD, so collect it and read more + os.write(buf, 0, bytes); + } + } while (bytes > 0); + + // Okay, we've got the report. + if (DEBUG) Slog.v(TAG, "processing"); + + // Mark the process record as being a native crash so that the + // cleanup mechanism knows we're still submitting the report even + // though the process will vanish as soon as we let debuggerd + // proceed. This isn't relevant for recoverable crashes, as we don't + // show the user an "app crashed" dialogue because the app (by + // design) didn't crash. + if (!gwpAsanRecoverableCrash) { + synchronized (mAm) { + synchronized (mAm.mProcLock) { + pr.mErrorState.setCrashing(true); + pr.mErrorState.setForceCrashReport(true); } - - // Crash reporting is synchronous but we want to let debuggerd - // go about it business right away, so we spin off the actual - // reporting logic on a thread and let it take it's time. - final String reportString = new String(os.toByteArray(), "UTF-8"); - (new NativeCrashReporter(pr, signal, reportString)).start(); - } else { - Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid); } - } else { - Slog.e(TAG, "Bogus pid!"); } + + // Crash reporting is synchronous but we want to let debuggerd + // go about it business right away, so we spin off the actual + // reporting logic on a thread and let it take it's time. + final String reportString = new String(os.toByteArray(), "UTF-8"); + (new NativeCrashReporter(pr, signal, gwpAsanRecoverableCrash, reportString)).start(); } catch (Exception e) { Slog.e(TAG, "Exception dealing with report", e); // ugh, fail. diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 7a92434a4ba4..84a80993c4b2 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -24,6 +24,7 @@ import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; +import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; @@ -2273,6 +2274,15 @@ public class OomAdjuster { capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; } } + if ((cstate.getCurCapability() + & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0) { + if (clientProcState <= PROCESS_STATE_IMPORTANT_FOREGROUND) { + // This is used to grant network access to User Initiated Jobs. + if (cr.hasFlag(Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) { + capability |= PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; + } + } + } if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) { continue; @@ -3447,7 +3457,8 @@ public class OomAdjuster { final ProcessCachedOptimizerRecord opt = app.mOptRecord; // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze if (opt.isFrozen() && opt.shouldNotFreeze()) { - mCachedAppOptimizer.unfreezeAppLSP(app, oomAdjReason); + mCachedAppOptimizer.unfreezeAppLSP(app, + CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason)); return; } @@ -3457,7 +3468,8 @@ public class OomAdjuster { && !opt.shouldNotFreeze()) { mCachedAppOptimizer.freezeAppAsyncLSP(app); } else if (state.getSetAdj() < CACHED_APP_MIN_ADJ) { - mCachedAppOptimizer.unfreezeAppLSP(app, oomAdjReason); + mCachedAppOptimizer.unfreezeAppLSP(app, + CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason)); } } } diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 2517c9c1ea4b..1d48cb25f03a 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -493,7 +493,7 @@ class ProcessErrorStateRecord { StringWriter tracesFileException = new StringWriter(); // To hold the start and end offset to the ANR trace file respectively. final AtomicLong firstPidEndOffset = new AtomicLong(-1); - File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, + File tracesFile = StackTracesDumpHelper.dumpStackTraces(firstPids, isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids, nativePidsFuture, tracesFileException, firstPidEndOffset, annotation, criticalEventLog, auxiliaryTaskExecutor, latencyTracker); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 35f71f74d0e1..b26a1705b309 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2574,7 +2574,10 @@ public final class ProcessList { + ", " + reason); app.setPendingStart(false); killProcessQuiet(pid); - Process.killProcessGroup(app.uid, app.getPid()); + final int appPid = app.getPid(); + if (appPid != 0) { + Process.killProcessGroup(app.uid, appPid); + } noteAppKill(app, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_INVALID_START, reason); return false; @@ -4897,12 +4900,14 @@ public final class ProcessList { final boolean isAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getCurProcState(), uidRec.getCurCapability()) - || isProcStateAllowedWhileOnRestrictBackground(uidRec.getCurProcState()); + || isProcStateAllowedWhileOnRestrictBackground(uidRec.getCurProcState(), + uidRec.getCurCapability()); // Denotes whether uid's process state was previously allowed network access. final boolean wasAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getSetProcState(), uidRec.getSetCapability()) - || isProcStateAllowedWhileOnRestrictBackground(uidRec.getSetProcState()); + || isProcStateAllowedWhileOnRestrictBackground(uidRec.getSetProcState(), + uidRec.getSetCapability()); // When the uid is coming to foreground, AMS should inform the app thread that it should // block for the network rules to get updated before launching an activity. diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 4defdc6976e1..18ef66febe89 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -176,6 +176,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN boolean mAllowWhileInUsePermissionInFgs; // A copy of mAllowWhileInUsePermissionInFgs's value when the service is entering FGS state. boolean mAllowWhileInUsePermissionInFgsAtEntering; + /** Allow scheduling user-initiated jobs from the background. */ + boolean mAllowUiJobScheduling; // the most recent package that start/bind this service. String mRecentCallingPackage; @@ -607,6 +609,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs="); pw.println(mAllowWhileInUsePermissionInFgs); + pw.print(prefix); pw.print("allowUiJobScheduling="); pw.println(mAllowUiJobScheduling); pw.print(prefix); pw.print("recentCallingPackage="); pw.println(mRecentCallingPackage); pw.print(prefix); pw.print("recentCallingUid="); @@ -1024,7 +1027,17 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN ams.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT); } + void updateAllowUiJobScheduling(boolean allowUiJobScheduling) { + if (mAllowUiJobScheduling == allowUiJobScheduling) { + return; + } + mAllowUiJobScheduling = allowUiJobScheduling; + } + private void setAllowedBgActivityStartsByStart(BackgroundStartPrivileges newValue) { + if (mBackgroundStartPrivilegesByStartMerged == newValue) { + return; + } mBackgroundStartPrivilegesByStartMerged = newValue; updateParentProcessBgActivityStartsToken(); } diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java new file mode 100644 index 000000000000..937332894dbd --- /dev/null +++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import static android.text.format.DateUtils.DAY_IN_MILLIS; + +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; +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.os.Build; +import android.os.Debug; +import android.os.FileUtils; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.util.Slog; +import android.util.SparseBooleanArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.ProcessCpuTracker; +import com.android.internal.os.anr.AnrLatencyTracker; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + + +/** + * A helper for dumping stack traces. + */ +public class StackTracesDumpHelper { + static final String TAG = TAG_WITH_CLASS_NAME ? "StackTracesDumpHelper" : TAG_AM; + + @GuardedBy("StackTracesDumpHelper.class") + private static final SimpleDateFormat ANR_FILE_DATE_FORMAT = + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS"); + + static final String ANR_FILE_PREFIX = "anr_"; + public static final String ANR_TRACE_DIR = "/data/anr"; + + private static final int NATIVE_DUMP_TIMEOUT_MS = + 2000 * Build.HW_TIMEOUT_MULTIPLIER; // 2 seconds; + private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes. + + /** + * If a stack trace dump file is configured, dump process stack traces. + * @param firstPids of dalvik VM processes to dump stack traces for first + * @param lastPids of dalvik VM processes to dump stack traces for last + * @param nativePidsFuture optional future for a list of native pids to dump stack crawls + * @param logExceptionCreatingFile optional writer to which we log errors creating the file + * @param auxiliaryTaskExecutor executor to execute auxiliary tasks on + * @param latencyTracker the latency tracker instance of the current ANR. + */ + public static File dumpStackTraces(ArrayList<Integer> firstPids, + ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids, + Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile, + @NonNull Executor auxiliaryTaskExecutor, AnrLatencyTracker latencyTracker) { + return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture, + logExceptionCreatingFile, null, null, null, auxiliaryTaskExecutor, latencyTracker); + } + + /** + * @param subject the subject of the dumped traces + * @param criticalEventSection the critical event log, passed as a string + */ + public static File dumpStackTraces(ArrayList<Integer> firstPids, + ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids, + Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile, + String subject, String criticalEventSection, @NonNull Executor auxiliaryTaskExecutor, + AnrLatencyTracker latencyTracker) { + return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture, + logExceptionCreatingFile, null, subject, criticalEventSection, + auxiliaryTaskExecutor, latencyTracker); + } + + /** + * @param firstPidEndOffset Optional, when it's set, it receives the start/end offset + * of the very first pid to be dumped. + */ + /* package */ static File dumpStackTraces(ArrayList<Integer> firstPids, + ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids, + Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile, + AtomicLong firstPidEndOffset, String subject, String criticalEventSection, + @NonNull Executor auxiliaryTaskExecutor, AnrLatencyTracker latencyTracker) { + try { + + if (latencyTracker != null) { + latencyTracker.dumpStackTracesStarted(); + } + + Slog.i(TAG, "dumpStackTraces pids=" + lastPids); + + // Measure CPU usage as soon as we're called in order to get a realistic sampling + // of the top users at the time of the request. + Supplier<ArrayList<Integer>> extraPidsSupplier = processCpuTracker != null + ? () -> getExtraPids(processCpuTracker, lastPids, latencyTracker) : null; + Future<ArrayList<Integer>> extraPidsFuture = null; + if (extraPidsSupplier != null) { + extraPidsFuture = + CompletableFuture.supplyAsync(extraPidsSupplier, auxiliaryTaskExecutor); + } + + final File tracesDir = new File(ANR_TRACE_DIR); + + // NOTE: We should consider creating the file in native code atomically once we've + // gotten rid of the old scheme of dumping and lot of the code that deals with paths + // can be removed. + File tracesFile; + try { + tracesFile = createAnrDumpFile(tracesDir); + } catch (IOException e) { + Slog.w(TAG, "Exception creating ANR dump file:", e); + if (logExceptionCreatingFile != null) { + logExceptionCreatingFile.append( + "----- Exception creating ANR dump file -----\n"); + e.printStackTrace(new PrintWriter(logExceptionCreatingFile)); + } + if (latencyTracker != null) { + latencyTracker.anrSkippedDumpStackTraces(); + } + return null; + } + + if (subject != null || criticalEventSection != null) { + appendtoANRFile(tracesFile.getAbsolutePath(), + (subject != null ? "Subject: " + subject + "\n\n" : "") + + (criticalEventSection != null ? criticalEventSection : "")); + } + + long firstPidEndPos = dumpStackTraces( + tracesFile.getAbsolutePath(), firstPids, nativePidsFuture, + extraPidsFuture, latencyTracker); + if (firstPidEndOffset != null) { + firstPidEndOffset.set(firstPidEndPos); + } + // Each set of ANR traces is written to a separate file and dumpstate will process + // all such files and add them to a captured bug report if they're recent enough. + maybePruneOldTraces(tracesDir); + + return tracesFile; + } finally { + if (latencyTracker != null) { + latencyTracker.dumpStackTracesEnded(); + } + } + + } + + /** + * @return The end offset of the trace of the very first PID + */ + public static long dumpStackTraces(String tracesFile, + ArrayList<Integer> firstPids, Future<ArrayList<Integer>> nativePidsFuture, + Future<ArrayList<Integer>> extraPidsFuture, AnrLatencyTracker latencyTracker) { + + Slog.i(TAG, "Dumping to " + tracesFile); + + // We don't need any sort of inotify based monitoring when we're dumping traces via + // tombstoned. Data is piped to an "intercept" FD installed in tombstoned so we're in full + // control of all writes to the file in question. + + // We must complete all stack dumps within 20 seconds. + long remainingTime = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; + + // As applications are usually interested with the ANR stack traces, but we can't share with + // them the stack traces other than their own stacks. So after the very first PID is + // dumped, remember the current file size. + long firstPidEnd = -1; + + // First collect all of the stacks of the most important pids. + if (firstPids != null) { + if (latencyTracker != null) { + latencyTracker.dumpingFirstPidsStarted(); + } + + int num = firstPids.size(); + for (int i = 0; i < num; i++) { + final int pid = firstPids.get(i); + // We don't copy ANR traces from the system_server intentionally. + final boolean firstPid = i == 0 && ActivityManagerService.MY_PID != pid; + if (latencyTracker != null) { + latencyTracker.dumpingPidStarted(pid); + } + + Slog.i(TAG, "Collecting stacks for pid " + pid); + final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, + remainingTime); + if (latencyTracker != null) { + latencyTracker.dumpingPidEnded(); + } + + remainingTime -= timeTaken; + if (remainingTime <= 0) { + Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + pid + + "); deadline exceeded."); + return firstPidEnd; + } + + if (firstPid) { + firstPidEnd = new File(tracesFile).length(); + // Full latency dump + if (latencyTracker != null) { + appendtoANRFile(tracesFile, + latencyTracker.dumpAsCommaSeparatedArrayWithHeader()); + } + } + if (DEBUG_ANR) { + Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms"); + } + } + if (latencyTracker != null) { + latencyTracker.dumpingFirstPidsEnded(); + } + } + + // Next collect the stacks of the native pids + ArrayList<Integer> nativePids = collectPids(nativePidsFuture, "native pids"); + + Slog.i(TAG, "dumpStackTraces nativepids=" + nativePids); + + if (nativePids != null) { + if (latencyTracker != null) { + latencyTracker.dumpingNativePidsStarted(); + } + for (int pid : nativePids) { + Slog.i(TAG, "Collecting stacks for native pid " + pid); + final long nativeDumpTimeoutMs = Math.min(NATIVE_DUMP_TIMEOUT_MS, remainingTime); + + if (latencyTracker != null) { + latencyTracker.dumpingPidStarted(pid); + } + final long start = SystemClock.elapsedRealtime(); + Debug.dumpNativeBacktraceToFileTimeout( + pid, tracesFile, (int) (nativeDumpTimeoutMs / 1000)); + final long timeTaken = SystemClock.elapsedRealtime() - start; + if (latencyTracker != null) { + latencyTracker.dumpingPidEnded(); + } + remainingTime -= timeTaken; + if (remainingTime <= 0) { + Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid + + "); deadline exceeded."); + return firstPidEnd; + } + + if (DEBUG_ANR) { + Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms"); + } + } + if (latencyTracker != null) { + latencyTracker.dumpingNativePidsEnded(); + } + } + + // Lastly, dump stacks for all extra PIDs from the CPU tracker. + ArrayList<Integer> extraPids = collectPids(extraPidsFuture, "extra pids"); + + if (extraPidsFuture != null) { + try { + extraPids = extraPidsFuture.get(); + } catch (ExecutionException e) { + Slog.w(TAG, "Failed to collect extra pids", e.getCause()); + } catch (InterruptedException e) { + Slog.w(TAG, "Interrupted while collecting extra pids", e); + } + } + Slog.i(TAG, "dumpStackTraces extraPids=" + extraPids); + + if (extraPids != null) { + if (latencyTracker != null) { + latencyTracker.dumpingExtraPidsStarted(); + } + for (int pid : extraPids) { + Slog.i(TAG, "Collecting stacks for extra pid " + pid); + if (latencyTracker != null) { + latencyTracker.dumpingPidStarted(pid); + } + final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime); + if (latencyTracker != null) { + latencyTracker.dumpingPidEnded(); + } + remainingTime -= timeTaken; + if (remainingTime <= 0) { + Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid + + "); deadline exceeded."); + return firstPidEnd; + } + + if (DEBUG_ANR) { + Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms"); + } + } + if (latencyTracker != null) { + latencyTracker.dumpingExtraPidsEnded(); + } + } + // Append the dumping footer with the current uptime + appendtoANRFile(tracesFile, "----- dumping ended at " + SystemClock.uptimeMillis() + "\n"); + Slog.i(TAG, "Done dumping"); + + return firstPidEnd; + } + + private static synchronized File createAnrDumpFile(File tracesDir) throws IOException { + final String formattedDate = ANR_FILE_DATE_FORMAT.format(new Date()); + final File anrFile = new File(tracesDir, ANR_FILE_PREFIX + formattedDate); + + if (anrFile.createNewFile()) { + FileUtils.setPermissions(anrFile.getAbsolutePath(), 0600, -1, -1); // -rw------- + return anrFile; + } else { + throw new IOException("Unable to create ANR dump file: createNewFile failed"); + } + } + + private static ArrayList<Integer> getExtraPids(ProcessCpuTracker processCpuTracker, + SparseBooleanArray lastPids, AnrLatencyTracker latencyTracker) { + if (latencyTracker != null) { + latencyTracker.processCpuTrackerMethodsCalled(); + } + ArrayList<Integer> extraPids = new ArrayList<>(); + processCpuTracker.init(); + try { + Thread.sleep(200); + } catch (InterruptedException ignored) { + } + + processCpuTracker.update(); + + // We'll take the stack crawls of just the top apps using CPU. + final int workingStatsNumber = processCpuTracker.countWorkingStats(); + for (int i = 0; i < workingStatsNumber && extraPids.size() < 2; i++) { + ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i); + if (lastPids.indexOfKey(stats.pid) >= 0) { + if (DEBUG_ANR) { + Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid); + } + + extraPids.add(stats.pid); + } else { + Slog.i(TAG, + "Skipping next CPU consuming process, not a java proc: " + + stats.pid); + } + } + if (latencyTracker != null) { + latencyTracker.processCpuTrackerMethodsReturned(); + } + return extraPids; + } + + /** + * Prune all trace files that are more than a day old. + * + * NOTE: It might make sense to move this functionality to tombstoned eventually, along with a + * shift away from anr_XX and tombstone_XX to a more descriptive name. We do it here for now + * since it's the system_server that creates trace files for most ANRs. + */ + private static void maybePruneOldTraces(File tracesDir) { + final File[] files = tracesDir.listFiles(); + if (files == null) return; + + final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64); + final long now = System.currentTimeMillis(); + try { + Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed()); + for (int i = 0; i < files.length; ++i) { + if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) { + if (!files[i].delete()) { + Slog.w(TAG, "Unable to prune stale trace file: " + files[i]); + } + } + } + } catch (IllegalArgumentException e) { + // The modification times changed while we were sorting. Bail... + // https://issuetracker.google.com/169836837 + Slog.w(TAG, "tombstone modification times changed while sorting; not pruning", e); + } + } + /** + * Dump java traces for process {@code pid} to the specified file. If java trace dumping + * fails, a native backtrace is attempted. Note that the timeout {@code timeoutMs} only applies + * to the java section of the trace, a further {@code NATIVE_DUMP_TIMEOUT_MS} might be spent + * attempting to obtain native traces in the case of a failure. Returns the total time spent + * capturing traces. + */ + private static long dumpJavaTracesTombstoned(int pid, String fileName, long timeoutMs) { + final long timeStart = SystemClock.elapsedRealtime(); + int headerSize = writeUptimeStartHeaderForPid(pid, fileName); + boolean javaSuccess = Debug.dumpJavaBacktraceToFileTimeout(pid, fileName, + (int) (timeoutMs / 1000)); + if (javaSuccess) { + // Check that something is in the file, actually. Try-catch should not be necessary, + // but better safe than sorry. + try { + long size = new File(fileName).length(); + if ((size - headerSize) < JAVA_DUMP_MINIMUM_SIZE) { + Slog.w(TAG, "Successfully created Java ANR file is empty!"); + javaSuccess = false; + } + } catch (Exception e) { + Slog.w(TAG, "Unable to get ANR file size", e); + javaSuccess = false; + } + } + if (!javaSuccess) { + Slog.w(TAG, "Dumping Java threads failed, initiating native stack dump."); + if (!Debug.dumpNativeBacktraceToFileTimeout(pid, fileName, + (NATIVE_DUMP_TIMEOUT_MS / 1000))) { + Slog.w(TAG, "Native stack dump failed!"); + } + } + + return SystemClock.elapsedRealtime() - timeStart; + } + + private static int appendtoANRFile(String fileName, String text) { + try (FileOutputStream fos = new FileOutputStream(fileName, true)) { + byte[] header = text.getBytes(StandardCharsets.UTF_8); + fos.write(header); + return header.length; + } catch (IOException e) { + Slog.w(TAG, "Exception writing to ANR dump file:", e); + return 0; + } + } + + /* + * Writes a header containing the process id and the current system uptime. + */ + private static int writeUptimeStartHeaderForPid(int pid, String fileName) { + return appendtoANRFile(fileName, "----- dumping pid: " + pid + " at " + + SystemClock.uptimeMillis() + "\n"); + } + + private static ArrayList<Integer> collectPids(Future<ArrayList<Integer>> pidsFuture, + String logName) { + + ArrayList<Integer> pids = null; + + if (pidsFuture == null) { + return pids; + } + try { + pids = pidsFuture.get(); + } catch (ExecutionException e) { + Slog.w(TAG, "Failed to collect " + logName, e.getCause()); + } catch (InterruptedException e) { + Slog.w(TAG, "Interrupted while collecting " + logName , e); + } + return pids; + } + +} diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 1b378837e558..d926c2c7c7a8 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -2141,6 +2141,17 @@ class UserController implements Handler.Callback { final int observerCount = mUserSwitchObservers.beginBroadcast(); if (observerCount > 0) { + for (int i = 0; i < observerCount; i++) { + final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); + t.traceBegin("onBeforeUserSwitching-" + name); + try { + mUserSwitchObservers.getBroadcastItem(i).onBeforeUserSwitching(newUserId); + } catch (RemoteException e) { + // Ignore + } finally { + t.traceEnd(); + } + } final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); synchronized (mLock) { uss.switching = true; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5893f1efc505..d43687be6128 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -929,7 +929,7 @@ public class AudioService extends IAudioService.Stub // Defines the format for the connection "address" for ALSA devices public static String makeAlsaAddressString(int card, int device) { - return "card=" + card + ";device=" + device + ";"; + return "card=" + card + ";device=" + device; } public static final class Lifecycle extends SystemService { @@ -4424,13 +4424,14 @@ public class AudioService extends IAudioService.Stub return; } - // Forcefully set LE audio volume as a workaround, since in some cases - // (like the outgoing call) the value of 'device' is not DEVICE_OUT_BLE_* - // even when BLE is connected. + // In some cases (like the outgoing or rejected call) the value of 'device' is not + // DEVICE_OUT_BLE_* even when BLE is connected. Changing the volume level in such case + // may cuase the other devices volume level leaking into the LeAudio device settings. if (!AudioSystem.isLeAudioDeviceType(device)) { - Log.w(TAG, "setLeAudioVolumeOnModeUpdate got unexpected device=" + device - + ", forcing to device=" + AudioSystem.DEVICE_OUT_BLE_HEADSET); - device = AudioSystem.DEVICE_OUT_BLE_HEADSET; + Log.w(TAG, "setLeAudioVolumeOnModeUpdate ignoring invalid device=" + + device + ", mode=" + mode + ", index=" + index + " maxIndex=" + maxIndex + + " streamType=" + streamType); + return; } if (DEBUG_VOL) { @@ -11602,6 +11603,7 @@ public class AudioService extends IAudioService.Stub return false; } + final long token = Binder.clearCallingIdentity(); try { if (!projectionService.isCurrentProjection(projection)) { Log.w(TAG, "App passed invalid MediaProjection token"); @@ -11611,6 +11613,8 @@ public class AudioService extends IAudioService.Stub Log.e(TAG, "Can't call .isCurrentProjection() on IMediaProjectionManager" + projectionService.asBinder(), e); return false; + } finally { + Binder.restoreCallingIdentity(token); } try { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 01ffc7e29ac0..128ef0b2a802 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -82,7 +82,9 @@ import com.android.internal.widget.LockPatternUtils; import com.android.server.SystemService; import com.android.server.biometrics.Utils; import com.android.server.biometrics.log.BiometricContext; +import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricStateCallback; +import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -97,7 +99,9 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.function.Supplier; @@ -1138,12 +1142,28 @@ public class FingerprintService extends SystemService { if (Utils.isVirtualEnabled(getContext())) { Slog.i(TAG, "Sync virtual enrollments"); final int userId = ActivityManager.getCurrentUser(); + final CountDownLatch latch = new CountDownLatch(mRegistry.getProviders().size()); for (ServiceProvider provider : mRegistry.getProviders()) { for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) { - provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */, - true /* favorHalEnrollments */); + provider.scheduleInternalCleanup(props.sensorId, userId, + new ClientMonitorCallback() { + @Override + public void onClientFinished( + @NonNull BaseClientMonitor clientMonitor, + boolean success) { + latch.countDown(); + if (!success) { + Slog.e(TAG, "Sync virtual enrollments failed"); + } + } + }, true /* favorHalEnrollments */); } } + try { + latch.await(3, TimeUnit.SECONDS); + } catch (Exception e) { + Slog.e(TAG, "Failed to wait for sync finishing", e); + } } } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index ad5ae5f4d0d9..c3a4c2e389ac 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1419,6 +1419,7 @@ public final class DisplayManagerService extends SystemService { } if (projection != null) { + final long firstToken = Binder.clearCallingIdentity(); try { if (!getProjectionService().isCurrentProjection(projection)) { throw new SecurityException("Cannot create VirtualDisplay with " @@ -1427,6 +1428,8 @@ public final class DisplayManagerService extends SystemService { flags = projection.applyVirtualDisplayFlags(flags); } catch (RemoteException e) { throw new SecurityException("unable to validate media projection or flags"); + } finally { + Binder.restoreCallingIdentity(firstToken); } } @@ -1494,7 +1497,7 @@ public final class DisplayManagerService extends SystemService { throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); } - final long token = Binder.clearCallingIdentity(); + final long secondToken = Binder.clearCallingIdentity(); try { final int displayId; synchronized (mSyncRoot) { @@ -1566,7 +1569,7 @@ public final class DisplayManagerService extends SystemService { return displayId; } finally { - Binder.restoreCallingIdentity(token); + Binder.restoreCallingIdentity(secondToken); } } @@ -4600,7 +4603,8 @@ public final class DisplayManagerService extends SystemService { public void onDesiredDisplayModeSpecsChanged() { synchronized (mSyncRoot) { mChanged = false; - mLogicalDisplayMapper.forEachLocked(mSpecsChangedConsumer); + mLogicalDisplayMapper.forEachLocked(mSpecsChangedConsumer, + /* includeDisabled= */ false); if (mChanged) { scheduleTraversalLocked(false); mChanged = false; diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 656882f3f615..f5859eed34f1 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1634,7 +1634,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAppliedAutoBrightness = false; brightnessAdjustmentFlags = 0; } - // Use default brightness when dozing unless overridden. if ((Float.isNaN(brightnessState)) && Display.isDozeState(state)) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index 3e01222bbae6..5306ac0e57b9 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -64,6 +64,7 @@ import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.FrameworkStatsLog; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.RingBuffer; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; @@ -72,6 +73,7 @@ import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.BrightnessUtils; import com.android.server.display.brightness.DisplayBrightnessController; +import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy; import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal; import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener; import com.android.server.display.layout.Layout; @@ -209,9 +211,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // True if auto-brightness should be used. private boolean mUseSoftwareAutoBrightnessConfig; - // True if the brightness config has changed and the short-term model needs to be reset - private boolean mShouldResetShortTermModel; - // Whether or not the color fade on screen on / off is enabled. private final boolean mColorFadeEnabled; @@ -296,12 +295,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // If the last recorded screen state was dozing or not. private boolean mDozing; - // Remembers whether certain kinds of brightness adjustments - // were recently applied so that we can decide how to transition. - private boolean mAppliedAutoBrightness; private boolean mAppliedDimming; private boolean mAppliedLowPower; - private boolean mAppliedTemporaryAutoBrightnessAdjustment; private boolean mAppliedThrottling; // Reason for which the brightness was last changed. See {@link BrightnessReason} for more @@ -359,6 +354,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // Tracks and manages the display state of the associated display. private final DisplayStateController mDisplayStateController; + + // Responsible for evaluating and tracking the automatic brightness relevant states. + // Todo: This is a temporary workaround. Ideally DPC2 should never talk to the strategies + private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy; + // A record of state for skipping brightness ramps. private int mSkipRampState = RAMP_STATE_SKIP_NONE; @@ -385,24 +385,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal @Nullable private BrightnessMappingStrategy mIdleModeBrightnessMapper; - // The current brightness configuration. - @Nullable - private BrightnessConfiguration mBrightnessConfiguration; - - // The last auto brightness adjustment that was set by the user and not temporary. Set to - // Float.NaN when an auto-brightness adjustment hasn't been recorded yet. - private float mAutoBrightnessAdjustment; - - // The pending auto brightness adjustment that will take effect on the next power state update. - private float mPendingAutoBrightnessAdjustment; - - // The temporary auto brightness adjustment. Typically set when a user is interacting with the - // adjustment slider but hasn't settled on a choice yet. Set to - // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set. - private float mTemporaryAutoBrightnessAdjustment; - - private boolean mUseAutoBrightness; - private boolean mIsRbcActive; // Animators. @@ -454,6 +436,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal () -> updatePowerState(), mDisplayId, mSensorManager); mHighBrightnessModeMetadata = hbmMetadata; mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController); + mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(context, mDisplayId); mTag = "DisplayPowerController2[" + mDisplayId + "]"; mBrightnessThrottlingDataId = logicalDisplay.getBrightnessThrottlingDataIdLocked(); @@ -555,9 +538,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mBrightnessBucketsInDozeConfig = resources.getBoolean( R.bool.config_displayBrightnessBucketsInDoze); - mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); - mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; mBootCompleted = bootCompleted; } @@ -1038,6 +1018,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mDisplayBrightnessController.setAutomaticBrightnessController( mAutomaticBrightnessController); + mAutomaticBrightnessStrategy + .setAutomaticBrightnessController(mAutomaticBrightnessController); mBrightnessEventRingBuffer = new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_MAX); @@ -1168,7 +1150,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal final boolean mustNotify; final int previousPolicy; boolean mustInitialize = false; - int brightnessAdjustmentFlags = 0; mBrightnessReasonTemp.set(null); mTempBrightnessEvent.reset(); SparseArray<DisplayPowerControllerInterface> displayBrightnessFollowers; @@ -1208,7 +1189,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal .updateDisplayState(mPowerRequest, mIsEnabled, mIsInTransition); if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.setLightSensorEnabled(mUseAutoBrightness + mScreenOffBrightnessSensorController + .setLightSensorEnabled(mAutomaticBrightnessStrategy.shouldUseAutoBrightness() && mIsEnabled && (state == Display.STATE_OFF || (state == Display.STATE_DOZE && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig())) && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); @@ -1222,7 +1204,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // Animate the screen state change unless already animating. // The transition may be deferred, so after this point we will use the // actual state instead of the desired one. - final int oldState = mPowerState.getScreenState(); animateScreenStateChange(state, mDisplayStateController.shouldPerformScreenOffTransition()); state = mPowerState.getScreenState(); @@ -1231,112 +1212,59 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal float brightnessState = displayBrightnessState.getBrightness(); float rawBrightnessState = displayBrightnessState.getBrightness(); mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason()); - - final boolean autoBrightnessEnabledInDoze = - mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig() - && Display.isDozeState(state); - final boolean autoBrightnessEnabled = mUseAutoBrightness - && (state == Display.STATE_ON || autoBrightnessEnabledInDoze) - && (Float.isNaN(brightnessState) - || mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_TEMPORARY - || mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_BOOST) - && mAutomaticBrightnessController != null - && mBrightnessReasonTemp.getReason() != BrightnessReason.REASON_FOLLOWER; - final boolean autoBrightnessDisabledDueToDisplayOff = mUseAutoBrightness - && !(state == Display.STATE_ON || autoBrightnessEnabledInDoze); - final int autoBrightnessState = autoBrightnessEnabled - ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED - : autoBrightnessDisabledDueToDisplayOff - ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE - : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED; - final boolean userSetBrightnessChanged = mDisplayBrightnessController .updateUserSetScreenBrightness(); - - final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment(); - - // Use the autobrightness adjustment override if set. - final float autoBrightnessAdjustment; - if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) { - autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment; - brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO_TEMP; - mAppliedTemporaryAutoBrightnessAdjustment = true; - } else { - autoBrightnessAdjustment = mAutoBrightnessAdjustment; - brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO; - mAppliedTemporaryAutoBrightnessAdjustment = false; - } + // Take note if the short term model was already active before applying the current + // request changes. + final boolean wasShortTermModelActive = + mAutomaticBrightnessStrategy.isShortTermModelActive(); + mAutomaticBrightnessStrategy.setAutoBrightnessState(state, + mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(), + brightnessState, mBrightnessReasonTemp.getReason(), mPowerRequest.policy, + mDisplayBrightnessController.getLastUserSetScreenBrightness(), + userSetBrightnessChanged); // If the brightness is already set then it's been overridden by something other than the // user, or is a temporary adjustment. boolean userInitiatedChange = (Float.isNaN(brightnessState)) - && (autoBrightnessAdjustmentChanged || userSetBrightnessChanged); - boolean wasShortTermModelActive = false; - // Configure auto-brightness. - if (mAutomaticBrightnessController != null) { - wasShortTermModelActive = mAutomaticBrightnessController.hasUserDataPoints(); - mAutomaticBrightnessController.configure(autoBrightnessState, - mBrightnessConfiguration, - mDisplayBrightnessController.getLastUserSetScreenBrightness(), - userSetBrightnessChanged, autoBrightnessAdjustment, - autoBrightnessAdjustmentChanged, mPowerRequest.policy, - mShouldResetShortTermModel); - mShouldResetShortTermModel = false; - } - mHbmController.setAutoBrightnessEnabled(mUseAutoBrightness + && (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged() + || userSetBrightnessChanged); + + mHbmController.setAutoBrightnessEnabled(mAutomaticBrightnessStrategy + .shouldUseAutoBrightness() ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); - if (mBrightnessTracker != null) { - mBrightnessTracker.setShouldCollectColorSample(mBrightnessConfiguration != null - && mBrightnessConfiguration.shouldCollectColorSamples()); - } - boolean updateScreenBrightnessSetting = false; float currentBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness(); // Apply auto-brightness. boolean slowChange = false; + int brightnessAdjustmentFlags = 0; if (Float.isNaN(brightnessState)) { - float newAutoBrightnessAdjustment = autoBrightnessAdjustment; - if (autoBrightnessEnabled) { - rawBrightnessState = mAutomaticBrightnessController - .getRawAutomaticScreenBrightness(); - brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness( - mTempBrightnessEvent); - newAutoBrightnessAdjustment = - mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment(); - } - if (BrightnessUtils.isValidBrightnessValue(brightnessState) - || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) { - // Use current auto-brightness value and slowly adjust to changes. - brightnessState = clampScreenBrightness(brightnessState); - if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) { - slowChange = true; // slowly adapt to auto-brightness - } - updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState; - mAppliedAutoBrightness = true; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC); - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.setLightSensorEnabled(false); + if (mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()) { + brightnessState = mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(); + if (BrightnessUtils.isValidBrightnessValue(brightnessState) + || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) { + rawBrightnessState = mAutomaticBrightnessController + .getRawAutomaticScreenBrightness(); + brightnessState = clampScreenBrightness(brightnessState); + // slowly adapt to auto-brightness + slowChange = mAutomaticBrightnessStrategy.hasAppliedAutoBrightness() + && !mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged(); + brightnessAdjustmentFlags = + mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags(); + updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState; + mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC); + if (mScreenOffBrightnessSensorController != null) { + mScreenOffBrightnessSensorController.setLightSensorEnabled(false); + } } - } else { - mAppliedAutoBrightness = false; - } - if (autoBrightnessAdjustment != newAutoBrightnessAdjustment) { - // If the autobrightness controller has decided to change the adjustment value - // used, make sure that's reflected in settings. - putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment); - } else { - // Adjustment values resulted in no change - brightnessAdjustmentFlags = 0; } } else { // Any non-auto-brightness values such as override or temporary should still be subject // to clamping so that they don't go beyond the current max as specified by HBM // Controller. brightnessState = clampScreenBrightness(brightnessState); - mAppliedAutoBrightness = false; - brightnessAdjustmentFlags = 0; } // Use default brightness when dozing unless overridden. @@ -1349,7 +1277,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // The ALS is not available yet - use the screen off sensor to determine the initial // brightness - if (Float.isNaN(brightnessState) && autoBrightnessEnabled + if (Float.isNaN(brightnessState) && mAutomaticBrightnessStrategy.isAutoBrightnessEnabled() && mScreenOffBrightnessSensorController != null) { rawBrightnessState = mScreenOffBrightnessSensorController.getAutomaticScreenBrightness(); @@ -1466,7 +1394,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal boolean brightnessAdjusted = false; final boolean brightnessIsTemporary = (mBrightnessReason.getReason() == BrightnessReason.REASON_TEMPORARY) - || mAppliedTemporaryAutoBrightnessAdjustment; + || mAutomaticBrightnessStrategy + .isTemporaryAutoBrightnessAdjustmentApplied(); if (!mPendingScreenOff) { if (mSkipScreenOnBrightnessRamp) { if (state == Display.STATE_ON) { @@ -1524,6 +1453,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal final float currentBrightness = mPowerState.getScreenBrightness(); final float currentSdrBrightness = mPowerState.getSdrScreenBrightness(); + if (BrightnessUtils.isValidBrightnessValue(animateValue) && (animateValue != currentBrightness || sdrAnimateValue != currentSdrBrightness)) { @@ -1605,7 +1535,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mTempBrightnessEvent.setWasShortTermModelActive(wasShortTermModelActive); mTempBrightnessEvent.setDisplayBrightnessStrategyName(displayBrightnessState .getDisplayBrightnessStrategyName()); - mTempBrightnessEvent.setAutomaticBrightnessEnabled(mUseAutoBrightness); + mTempBrightnessEvent.setAutomaticBrightnessEnabled(mAutomaticBrightnessStrategy + .shouldUseAutoBrightness()); // Temporary is what we use during slider interactions. We avoid logging those so that // we don't spam logcat when the slider is being used. boolean tempToTempTransition = @@ -2151,13 +2082,12 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mDisplayBrightnessController .setPendingScreenBrightness(mDisplayBrightnessController .getScreenBrightnessSetting()); - mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(userSwitch); if (userSwitch) { // Don't treat user switches as user initiated change. mDisplayBrightnessController .setAndNotifyCurrentScreenBrightness(mDisplayBrightnessController .getPendingScreenBrightness()); - updateAutoBrightnessAdjustment(); if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.resetShortTermModel(); } @@ -2171,8 +2101,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); mHandler.postAtTime(() -> { - mUseAutoBrightness = screenBrightnessModeSetting - == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; + mAutomaticBrightnessStrategy.setUseAutoBrightness(screenBrightnessModeSetting + == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); updatePowerState(); }, mClock.uptimeMillis()); } @@ -2220,33 +2150,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal sendUpdatePowerState(); } - private void putAutoBrightnessAdjustmentSetting(float adjustment) { - if (mDisplayId == Display.DEFAULT_DISPLAY) { - mAutoBrightnessAdjustment = adjustment; - Settings.System.putFloatForUser(mContext.getContentResolver(), - Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, - UserHandle.USER_CURRENT); - } - } - - private boolean updateAutoBrightnessAdjustment() { - if (Float.isNaN(mPendingAutoBrightnessAdjustment)) { - return false; - } - if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) { - mPendingAutoBrightnessAdjustment = Float.NaN; - return false; - } - mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment; - mPendingAutoBrightnessAdjustment = Float.NaN; - mTemporaryAutoBrightnessAdjustment = Float.NaN; - return true; - } - private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated, boolean wasShortTermModelActive) { final float brightnessInNits = mDisplayBrightnessController.convertToNits(brightness); - if (mUseAutoBrightness && brightnessInNits >= 0.0f + if (mAutomaticBrightnessStrategy.shouldUseAutoBrightness() && brightnessInNits >= 0.0f && mAutomaticBrightnessController != null && mBrightnessTracker != null) { // We only want to track changes on devices that can actually map the display backlight // values into a physical brightness unit since the value provided by the API is in @@ -2329,16 +2236,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal pw.println(); pw.println("Display Power Controller Thread State:"); pw.println(" mPowerRequest=" + mPowerRequest); - pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment); pw.println(" mBrightnessReason=" + mBrightnessReason); - pw.println(" mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment); - pw.println(" mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment); - pw.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness); pw.println(" mAppliedDimming=" + mAppliedDimming); pw.println(" mAppliedLowPower=" + mAppliedLowPower); pw.println(" mAppliedThrottling=" + mAppliedThrottling); - pw.println(" mAppliedTemporaryAutoBrightnessAdjustment=" - + mAppliedTemporaryAutoBrightnessAdjustment); pw.println(" mDozing=" + mDozing); pw.println(" mSkipRampState=" + skipRampStateToString(mSkipRampState)); pw.println(" mScreenOnBlockStartRealTime=" + mScreenOnBlockStartRealTime); @@ -2349,6 +2250,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal pw.println(" mReportedToPolicy=" + reportedToPolicyToString(mReportedScreenStateToPolicy)); pw.println(" mIsRbcActive=" + mIsRbcActive); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + mAutomaticBrightnessStrategy.dump(ipw); if (mScreenBrightnessRampAnimator != null) { pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" @@ -2580,8 +2483,15 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } break; case MSG_CONFIGURE_BRIGHTNESS: - mBrightnessConfiguration = (BrightnessConfiguration) msg.obj; - mShouldResetShortTermModel = msg.arg1 == 1; + BrightnessConfiguration brightnessConfiguration = + (BrightnessConfiguration) msg.obj; + mAutomaticBrightnessStrategy.setBrightnessConfiguration(brightnessConfiguration, + msg.arg1 == 1); + if (mBrightnessTracker != null) { + mBrightnessTracker + .setShouldCollectColorSample(brightnessConfiguration != null + && brightnessConfiguration.shouldCollectColorSamples()); + } updatePowerState(); break; @@ -2593,7 +2503,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal break; case MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT: - mTemporaryAutoBrightnessAdjustment = Float.intBitsToFloat(msg.arg1); + mAutomaticBrightnessStrategy + .setTemporaryAutoBrightnessAdjustment(Float.intBitsToFloat(msg.arg1)); updatePowerState(); break; diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 250ba4350f1d..424eedc876ec 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -302,9 +302,16 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } public void forEachLocked(Consumer<LogicalDisplay> consumer) { + forEachLocked(consumer, /* includeDisabled= */ true); + } + + public void forEachLocked(Consumer<LogicalDisplay> consumer, boolean includeDisabled) { final int count = mLogicalDisplays.size(); for (int i = 0; i < count; i++) { - consumer.accept(mLogicalDisplays.valueAt(i)); + LogicalDisplay display = mLogicalDisplays.valueAt(i); + if (display.isEnabledLocked() || includeDisabled) { + consumer.accept(display); + } } } diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index e8327018e144..e3d38e7a25e9 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -16,6 +16,7 @@ package com.android.server.display; +import android.app.BroadcastOptions; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -421,6 +422,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { // Runs on the handler. private void handleSendStatusChangeBroadcast() { final Intent intent; + final BroadcastOptions options; synchronized (getSyncRoot()) { if (!mPendingStatusChangeBroadcast) { return; @@ -431,10 +433,13 @@ final class WifiDisplayAdapter extends DisplayAdapter { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS, getWifiDisplayStatusLocked()); + + options = BroadcastOptions.makeBasic(); + options.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); } // Send protected broadcast about wifi display status to registered receivers. - getContext().sendBroadcastAsUser(intent, UserHandle.ALL); + getContext().sendBroadcastAsUser(intent, UserHandle.ALL, null, options.toBundle()); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java new file mode 100644 index 000000000000..f6cf866dfa2f --- /dev/null +++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.display.brightness.strategy; + +import android.annotation.Nullable; +import android.content.Context; +import android.hardware.display.BrightnessConfiguration; +import android.os.PowerManager; +import android.os.UserHandle; +import android.provider.Settings; +import android.view.Display; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.AutomaticBrightnessController; +import com.android.server.display.brightness.BrightnessReason; +import com.android.server.display.brightness.BrightnessUtils; + +import java.io.PrintWriter; + +/** + * Helps manage the brightness based on the ambient environment (Ambient Light/lux sensor) using + * mappings from lux to nits to brightness, configured in the + * {@link com.android.server.display.DisplayDeviceConfig} class. This class inherently assumes + * that it is being executed from the power thread, and hence doesn't synchronize + * any of its resources + */ +public class AutomaticBrightnessStrategy { + private final Context mContext; + // The DisplayId of the associated logical display + private final int mDisplayId; + // The last auto brightness adjustment that was set by the user and is not temporary. Set to + // Float.NaN when an auto-brightness adjustment hasn't been recorded yet. + private float mAutoBrightnessAdjustment; + // The pending auto brightness adjustment that will take effect on the next power state update. + private float mPendingAutoBrightnessAdjustment; + // The temporary auto brightness adjustment. This was historically used when a user interacts + // with the adjustment slider but hasn't settled on a choice yet. + // Set to PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set. + private float mTemporaryAutoBrightnessAdjustment; + // Indicates if the temporary auto brightness adjustment has been applied while updating the + // associated display brightness + private boolean mAppliedTemporaryAutoBrightnessAdjustment; + // Indicates if the auto brightness adjustment has happened. + private boolean mAutoBrightnessAdjustmentChanged; + // Indicates the reasons for the auto-brightness adjustment + private int mAutoBrightnessAdjustmentReasonsFlags = 0; + // Indicates if the short term model should be reset before fetching the new brightness + // Todo(273543270): Short term model is an internal information of + // AutomaticBrightnessController and shouldn't be exposed outside of that class + private boolean mShouldResetShortTermModel = false; + // Remembers whether the auto-brightness has been applied in the latest brightness update. + private boolean mAppliedAutoBrightness = false; + // The controller for the automatic brightness level. + @Nullable + private AutomaticBrightnessController mAutomaticBrightnessController; + // The system setting denoting if the auto-brightness for the current user is enabled or not + private boolean mUseAutoBrightness = false; + // Indicates if the auto-brightness is currently enabled or not. It's possible that even if + // the user has enabled the auto-brightness from the settings, it is disabled because the + // display is off + private boolean mIsAutoBrightnessEnabled = false; + // If the auto-brightness model for the last manual changes done by the user. + private boolean mIsShortTermModelActive = false; + + // The BrightnessConfiguration currently being used + // Todo(273543270): BrightnessConfiguration is an internal implementation detail of + // AutomaticBrightnessController, and AutomaticBrightnessStrategy shouldn't be aware of its + // existence. + @Nullable + private BrightnessConfiguration mBrightnessConfiguration; + + public AutomaticBrightnessStrategy(Context context, int displayId) { + mContext = context; + mDisplayId = displayId; + mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); + mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; + mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; + } + + /** + * Sets up the automatic brightness states of this class. Also configures + * AutomaticBrightnessController accounting for any manual changes made by the user. + */ + public void setAutoBrightnessState(int targetDisplayState, + boolean allowAutoBrightnessWhileDozingConfig, + float brightnessState, int brightnessReason, int policy, + float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) { + final boolean autoBrightnessEnabledInDoze = + allowAutoBrightnessWhileDozingConfig + && Display.isDozeState(targetDisplayState); + mIsAutoBrightnessEnabled = shouldUseAutoBrightness() + && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze) + && (Float.isNaN(brightnessState) + || brightnessReason == BrightnessReason.REASON_TEMPORARY + || brightnessReason == BrightnessReason.REASON_BOOST) + && mAutomaticBrightnessController != null + && brightnessReason != BrightnessReason.REASON_FOLLOWER; + final boolean autoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness() + && !(targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze); + final int autoBrightnessState = mIsAutoBrightnessEnabled + ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED + : autoBrightnessDisabledDueToDisplayOff + ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE + : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED; + + accommodateUserBrightnessChanges(userSetBrightnessChanged, lastUserSetScreenBrightness, + policy, mBrightnessConfiguration, autoBrightnessState); + } + + public boolean isAutoBrightnessEnabled() { + return mIsAutoBrightnessEnabled; + } + + /** + * Updates the {@link BrightnessConfiguration} that is currently being used by the associated + * display. + */ + public void setBrightnessConfiguration(BrightnessConfiguration brightnessConfiguration, + boolean shouldResetShortTermModel) { + mBrightnessConfiguration = brightnessConfiguration; + setShouldResetShortTermModel(shouldResetShortTermModel); + } + + /** + * Promotes the pending auto-brightness adjustments which are yet to be applied to the current + * adjustments. Note that this is not applying the new adjustments to the AutoBrightness mapping + * strategies, but is only accommodating the changes in this class. + */ + public boolean processPendingAutoBrightnessAdjustments() { + mAutoBrightnessAdjustmentChanged = false; + if (Float.isNaN(mPendingAutoBrightnessAdjustment)) { + return false; + } + if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) { + mPendingAutoBrightnessAdjustment = Float.NaN; + return false; + } + mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment; + mPendingAutoBrightnessAdjustment = Float.NaN; + mTemporaryAutoBrightnessAdjustment = Float.NaN; + mAutoBrightnessAdjustmentChanged = true; + return true; + } + + /** + * Updates the associated AutomaticBrightnessController + */ + public void setAutomaticBrightnessController( + AutomaticBrightnessController automaticBrightnessController) { + if (automaticBrightnessController == mAutomaticBrightnessController) { + return; + } + if (mAutomaticBrightnessController != null) { + mAutomaticBrightnessController.stop(); + } + mAutomaticBrightnessController = automaticBrightnessController; + } + + /** + * Returns if the auto-brightness of the associated display has been enabled or not + */ + public boolean shouldUseAutoBrightness() { + return mUseAutoBrightness; + } + + /** + * Sets the auto-brightness state of the associated display. Called when the user makes a change + * in the system setting to enable/disable the auto-brightness. + */ + public void setUseAutoBrightness(boolean useAutoBrightness) { + mUseAutoBrightness = useAutoBrightness; + } + + /** + * Returns if the user made brightness change events(Typically when they interact with the + * brightness slider) were accommodated in the auto-brightness mapping strategies. This doesn't + * account for the latest changes that have been made by the user. + */ + public boolean isShortTermModelActive() { + return mIsShortTermModelActive; + } + + /** + * Sets the pending auto-brightness adjustments in the system settings. Executed + * when there is a change in the brightness system setting, or when there is a user switch. + */ + public void updatePendingAutoBrightnessAdjustments(boolean userSwitch) { + final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT); + mPendingAutoBrightnessAdjustment = Float.isNaN(adj) ? Float.NaN + : BrightnessUtils.clampAbsoluteBrightness(adj); + if (userSwitch) { + processPendingAutoBrightnessAdjustments(); + } + } + + /** + * Sets the temporary auto-brightness adjustments + */ + public void setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment) { + mTemporaryAutoBrightnessAdjustment = temporaryAutoBrightnessAdjustment; + } + + /** + * Dumps the state of this class. + */ + public void dump(PrintWriter writer) { + writer.println("AutomaticBrightnessStrategy:"); + writer.println(" mDisplayId=" + mDisplayId); + writer.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment); + writer.println(" mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment); + writer.println( + " mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment); + writer.println(" mShouldResetShortTermModel=" + mShouldResetShortTermModel); + writer.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness); + writer.println(" mAutoBrightnessAdjustmentChanged=" + mAutoBrightnessAdjustmentChanged); + writer.println(" mAppliedTemporaryAutoBrightnessAdjustment=" + + mAppliedTemporaryAutoBrightnessAdjustment); + writer.println(" mUseAutoBrightness=" + mUseAutoBrightness); + writer.println(" mWasShortTermModelActive=" + mIsShortTermModelActive); + writer.println(" mAutoBrightnessAdjustmentReasonsFlags=" + + mAutoBrightnessAdjustmentReasonsFlags); + } + + /** + * Indicates if any auto-brightness adjustments have happened since the last auto-brightness was + * set. + */ + public boolean getAutoBrightnessAdjustmentChanged() { + return mAutoBrightnessAdjustmentChanged; + } + + /** + * Returns whether the latest temporary auto-brightness adjustments have been applied or not + */ + public boolean isTemporaryAutoBrightnessAdjustmentApplied() { + return mAppliedTemporaryAutoBrightnessAdjustment; + } + + /** + * Evaluates the target automatic brightness of the associated display. + */ + public float getAutomaticScreenBrightness() { + float brightness = (mAutomaticBrightnessController != null) + ? mAutomaticBrightnessController.getAutomaticScreenBrightness() + : PowerManager.BRIGHTNESS_INVALID_FLOAT; + adjustAutomaticBrightnessStateIfValid(brightness); + return brightness; + } + + /** + * Gets the auto-brightness adjustment flag change reason + */ + public int getAutoBrightnessAdjustmentReasonsFlags() { + return mAutoBrightnessAdjustmentReasonsFlags; + } + + /** + * Returns if the auto brightness has been applied + */ + public boolean hasAppliedAutoBrightness() { + return mAppliedAutoBrightness; + } + + /** + * Used to adjust the state of this class when the automatic brightness value for the + * associated display is valid + */ + @VisibleForTesting + void adjustAutomaticBrightnessStateIfValid(float brightnessState) { + mAutoBrightnessAdjustmentReasonsFlags = isTemporaryAutoBrightnessAdjustmentApplied() + ? BrightnessReason.ADJUSTMENT_AUTO_TEMP + : BrightnessReason.ADJUSTMENT_AUTO; + mAppliedAutoBrightness = BrightnessUtils.isValidBrightnessValue(brightnessState) + || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT; + float newAutoBrightnessAdjustment = + (mAutomaticBrightnessController != null) + ? mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment() + : 0.0f; + if (!Float.isNaN(newAutoBrightnessAdjustment) + && mAutoBrightnessAdjustment != newAutoBrightnessAdjustment) { + // If the auto-brightness controller has decided to change the adjustment value + // used, make sure that's reflected in settings. + putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment); + } else { + mAutoBrightnessAdjustmentReasonsFlags = 0; + } + } + + /** + * Sets up the system to reset the short term model. Note that this will not reset the model + * right away, but ensures that the reset happens whenever the next brightness change happens + */ + @VisibleForTesting + void setShouldResetShortTermModel(boolean shouldResetShortTermModel) { + mShouldResetShortTermModel = shouldResetShortTermModel; + } + + @VisibleForTesting + boolean shouldResetShortTermModel() { + return mShouldResetShortTermModel; + } + + @VisibleForTesting + float getAutoBrightnessAdjustment() { + return mAutoBrightnessAdjustment; + } + + @VisibleForTesting + float getPendingAutoBrightnessAdjustment() { + return mPendingAutoBrightnessAdjustment; + } + + @VisibleForTesting + float getTemporaryAutoBrightnessAdjustment() { + return mTemporaryAutoBrightnessAdjustment; + } + + @VisibleForTesting + void putAutoBrightnessAdjustmentSetting(float adjustment) { + if (mDisplayId == Display.DEFAULT_DISPLAY) { + mAutoBrightnessAdjustment = adjustment; + Settings.System.putFloatForUser(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, + UserHandle.USER_CURRENT); + } + } + + /** + * Sets if the auto-brightness is applied on the latest brightness change. + */ + @VisibleForTesting + void setAutoBrightnessApplied(boolean autoBrightnessApplied) { + mAppliedAutoBrightness = autoBrightnessApplied; + } + + /** + * Accommodates the latest manual changes made by the user. Also updates {@link + * AutomaticBrightnessController} about the changes and configures it accordingly. + */ + @VisibleForTesting + void accommodateUserBrightnessChanges(boolean userSetBrightnessChanged, + float lastUserSetScreenBrightness, int policy, + BrightnessConfiguration brightnessConfiguration, int autoBrightnessState) { + // Update the pending auto-brightness adjustments if any. This typically checks and adjusts + // the state of the class if the user moves the brightness slider and has settled to a + // different value + processPendingAutoBrightnessAdjustments(); + // Update the temporary auto-brightness adjustments if any. This typically checks and + // adjusts the state of this class if the user is in the process of moving the brightness + // slider, but hasn't settled to any value yet + float autoBrightnessAdjustment = updateTemporaryAutoBrightnessAdjustments(); + mIsShortTermModelActive = false; + // Configure auto-brightness. + if (mAutomaticBrightnessController != null) { + // Accommodate user changes if any in the auto-brightness model + mAutomaticBrightnessController.configure(autoBrightnessState, + brightnessConfiguration, + lastUserSetScreenBrightness, + userSetBrightnessChanged, autoBrightnessAdjustment, + mAutoBrightnessAdjustmentChanged, policy, mShouldResetShortTermModel); + mShouldResetShortTermModel = false; + // We take note if the user brightness point is still being used in the current + // auto-brightness model. + mIsShortTermModelActive = mAutomaticBrightnessController.hasUserDataPoints(); + } + } + + /** + * Evaluates if there are any temporary auto-brightness adjustments which is not applied yet. + * Temporary brightness adjustments happen when the user moves the brightness slider in the + * auto-brightness mode, but hasn't settled to a value yet + */ + private float updateTemporaryAutoBrightnessAdjustments() { + mAppliedTemporaryAutoBrightnessAdjustment = + !Float.isNaN(mTemporaryAutoBrightnessAdjustment); + // We do not update the mAutoBrightnessAdjustment with mTemporaryAutoBrightnessAdjustment + // since we have not settled to a value yet + return mAppliedTemporaryAutoBrightnessAdjustment + ? mTemporaryAutoBrightnessAdjustment : mAutoBrightnessAdjustment; + } + + /** + * Returns the auto-brightness adjustment that is set in the system setting. + */ + private float getAutoBrightnessAdjustmentSetting() { + final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT); + return Float.isNaN(adj) ? 0.0f : BrightnessUtils.clampAbsoluteBrightness(adj); + } +} diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index c0deb3f8274b..805ff6611c29 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -3774,11 +3774,12 @@ public class HdmiControlService extends SystemService { } try { record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); + return true; } catch (RemoteException e) { Slog.e(TAG, "Failed to notify vendor command reception", e); } } - return true; + return false; } } diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java index abb8439092ac..9058c984f958 100644 --- a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java +++ b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java @@ -80,7 +80,7 @@ public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice { protected void handleEarcStateChange(@Constants.EarcStatus int status) { int oldEarcStatus; synchronized (mLock) { - HdmiLogger.debug(TAG, "eARC state change [old:%b new %b]", mEarcStatus, + HdmiLogger.debug("eARC state change [old:%b new %b]", mEarcStatus, status); oldEarcStatus = mEarcStatus; mEarcStatus = status; diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index efc4f11168bb..d0669e7602ed 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -547,6 +547,10 @@ public class InputManagerService extends IInputManager.Stub mBatteryController.systemRunning(); mKeyboardBacklightController.systemRunning(); mKeyRemapper.systemRunning(); + + mNative.setStylusPointerIconEnabled( + Objects.requireNonNull(mContext.getSystemService(InputManager.class)) + .isStylusPointerIconEnabled()); } private void reloadDeviceAliases() { @@ -2749,13 +2753,6 @@ public class InputManagerService extends IInputManager.Stub return null; } - // Native callback. - @SuppressWarnings("unused") - private boolean isStylusPointerIconEnabled() { - return Objects.requireNonNull(mContext.getSystemService(InputManager.class)) - .isStylusPointerIconEnabled(); - } - private static class PointerDisplayIdChangedArgs { final int mPointerDisplayId; final float mXPosition; diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java index 403323803fca..048308e75e80 100644 --- a/services/core/java/com/android/server/input/KeyboardBacklightController.java +++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java @@ -29,6 +29,8 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; +import android.os.UEventObserver; +import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.Slog; @@ -69,6 +71,8 @@ final class KeyboardBacklightController implements private static final int MAX_BRIGHTNESS = 255; private static final int NUM_BRIGHTNESS_CHANGE_STEPS = 10; + private static final String UEVENT_KEYBOARD_BACKLIGHT_TAG = "kbd_backlight"; + @VisibleForTesting static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis(); @@ -120,6 +124,18 @@ final class KeyboardBacklightController implements Message msg = Message.obtain(mHandler, MSG_UPDATE_EXISTING_DEVICES, inputManager.getInputDeviceIds()); mHandler.sendMessage(msg); + + // Observe UEvents for "kbd_backlight" sysfs nodes. + // We want to observe creation of such LED nodes since they might be created after device + // FD created and InputDevice creation logic doesn't initialize LED nodes which leads to + // backlight not working. + UEventObserver observer = new UEventObserver() { + @Override + public void onUEvent(UEvent event) { + onKeyboardBacklightUEvent(event); + } + }; + observer.startObserving(UEVENT_KEYBOARD_BACKLIGHT_TAG); } @Override @@ -386,6 +402,34 @@ final class KeyboardBacklightController implements } } + @VisibleForTesting + public void onKeyboardBacklightUEvent(UEventObserver.UEvent event) { + if ("ADD".equalsIgnoreCase(event.get("ACTION")) && "LEDS".equalsIgnoreCase( + event.get("SUBSYSTEM"))) { + final String devPath = event.get("DEVPATH"); + if (isValidBacklightNodePath(devPath)) { + mNative.sysfsNodeChanged("/sys" + devPath); + } + } + } + + private static boolean isValidBacklightNodePath(String devPath) { + if (TextUtils.isEmpty(devPath)) { + return false; + } + int index = devPath.lastIndexOf('/'); + if (index < 0) { + return false; + } + String backlightNode = devPath.substring(index + 1); + devPath = devPath.substring(0, index); + if (!devPath.endsWith("leds") || !backlightNode.contains("kbd_backlight")) { + return false; + } + index = devPath.lastIndexOf('/'); + return index >= 0; + } + @Override public void dump(PrintWriter pw) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw); diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java index 4d4a87e18664..72c7dadac271 100644 --- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java +++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java @@ -1261,30 +1261,45 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener { private static boolean isLayoutCompatibleWithLanguageTag(KeyboardLayout layout, @NonNull String languageTag) { - final int[] scriptsFromLanguageTag = UScript.getCode(Locale.forLanguageTag(languageTag)); - if (scriptsFromLanguageTag.length == 0) { - // If no scripts inferred from languageTag then allowing the layout - return true; - } - LocaleList locales = layout.getLocales(); - if (locales.isEmpty()) { + LocaleList layoutLocales = layout.getLocales(); + if (layoutLocales.isEmpty()) { // KCM file doesn't have an associated language tag. This can be from // a 3rd party app so need to include it as a potential layout. return true; } - for (int i = 0; i < locales.size(); i++) { - final Locale locale = locales.get(i); - if (locale == null) { - continue; - } - int[] scripts = UScript.getCode(locale); - if (scripts != null && haveCommonValue(scripts, scriptsFromLanguageTag)) { + // Match derived Script codes + final int[] scriptsFromLanguageTag = getScriptCodes(Locale.forLanguageTag(languageTag)); + if (scriptsFromLanguageTag.length == 0) { + // If no scripts inferred from languageTag then allowing the layout + return true; + } + for (int i = 0; i < layoutLocales.size(); i++) { + final Locale locale = layoutLocales.get(i); + int[] scripts = getScriptCodes(locale); + if (haveCommonValue(scripts, scriptsFromLanguageTag)) { return true; } } return false; } + private static int[] getScriptCodes(@Nullable Locale locale) { + if (locale == null) { + return new int[0]; + } + if (!TextUtils.isEmpty(locale.getScript())) { + int scriptCode = UScript.getCodeFromName(locale.getScript()); + if (scriptCode != UScript.INVALID_CODE) { + return new int[]{scriptCode}; + } + } + int[] scripts = UScript.getCode(locale); + if (scripts != null) { + return scripts; + } + return new int[0]; + } + private static boolean haveCommonValue(int[] arr1, int[] arr2) { for (int a1 : arr1) { for (int a2 : arr2) { diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index 5395302d1c32..aeb2477f8890 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -234,6 +234,15 @@ interface NativeInputManagerService { */ float[] getMouseCursorPosition(); + /** Set whether showing a pointer icon for styluses is enabled. */ + void setStylusPointerIconEnabled(boolean enabled); + + /** + * Report sysfs node changes. This may result in recreation of the corresponding InputDevice. + * The recreated device may contain new associated peripheral devices like Light, Battery, etc. + */ + void sysfsNodeChanged(String sysfsNodePath); + /** The native implementation of InputManagerService methods. */ class NativeImpl implements NativeInputManagerService { /** Pointer to native input manager service object, used by native code. */ @@ -478,5 +487,11 @@ interface NativeInputManagerService { @Override public native float[] getMouseCursorPosition(); + + @Override + public native void setStylusPointerIconEnabled(boolean enabled); + + @Override + public native void sysfsNodeChanged(String sysfsNodePath); } } diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java index d54354715d03..bb1a445b52e9 100644 --- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java +++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java @@ -24,8 +24,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UiThread; -import android.os.Handler; import android.hardware.input.InputManagerGlobal; +import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.text.TextUtils; @@ -165,7 +165,11 @@ final class HandwritingModeController { @NonNull String delegatePackageName, @NonNull String delegatorPackageName) { mDelegatePackageName = delegatePackageName; mDelegatorPackageName = delegatorPackageName; - mHandwritingBuffer.ensureCapacity(getHandwritingBufferSize()); + if (mHandwritingBuffer == null) { + mHandwritingBuffer = new ArrayList<>(getHandwritingBufferSize()); + } else { + mHandwritingBuffer.ensureCapacity(getHandwritingBufferSize()); + } scheduleHandwritingDelegationTimeout(); } diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java index ceb970683834..61fe6545f139 100644 --- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java +++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java @@ -284,7 +284,7 @@ public final class ImeVisibilityStateComputer { void setWindowState(IBinder windowToken, @NonNull ImeTargetWindowState newState) { final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken); - if (state != null && newState.hasEdiorFocused()) { + if (state != null && newState.hasEditorFocused()) { // Inherit the last requested IME visible state when the target window is still // focused with an editor. newState.setRequestedImeVisible(state.mRequestedImeVisible); @@ -340,7 +340,7 @@ public final class ImeVisibilityStateComputer { // state is ALWAYS_HIDDEN or STATE_HIDDEN with forward navigation). // Because the app might leverage these flags to hide soft-keyboard with showing their own // UI for input. - if (state.hasEdiorFocused() && shouldRestoreImeVisibility(state)) { + if (state.hasEditorFocused() && shouldRestoreImeVisibility(state)) { if (DEBUG) Slog.v(TAG, "Will show input to restore visibility"); // Inherit the last requested IME visible state when the target window is still // focused with an editor. @@ -352,7 +352,7 @@ public final class ImeVisibilityStateComputer { switch (softInputVisibility) { case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: - if (state.hasImeFocusChanged() && (!state.hasEdiorFocused() || !doAutoShow)) { + if (state.hasImeFocusChanged() && (!state.hasEditorFocused() || !doAutoShow)) { if (WindowManager.LayoutParams.mayUseInputMethod(state.getWindowFlags())) { // There is no focus view, and this window will // be behind any soft input window, so hide the @@ -361,7 +361,7 @@ public final class ImeVisibilityStateComputer { return new ImeVisibilityResult(STATE_HIDE_IME_NOT_ALWAYS, SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW); } - } else if (state.hasEdiorFocused() && doAutoShow && isForwardNavigation) { + } else if (state.hasEditorFocused() && doAutoShow && isForwardNavigation) { // There is a focus view, and we are navigating forward // into the window, so show the input window for the user. // We only do this automatically if the window can resize @@ -437,7 +437,7 @@ public final class ImeVisibilityStateComputer { SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR); } } - if (!state.hasEdiorFocused() && mInputShown && state.isStartInputByGainFocus() + if (!state.hasEditorFocused() && mInputShown && state.isStartInputByGainFocus() && mService.mInputMethodDeviceConfigs.shouldHideImeWhenNoEditorFocus()) { // Hide the soft-keyboard when the system do nothing for softInputModeState // of the window being gained focus without an editor. This behavior benefits @@ -620,7 +620,7 @@ public final class ImeVisibilityStateComputer { return mImeFocusChanged; } - boolean hasEdiorFocused() { + boolean hasEditorFocused() { return mHasFocusedEditor; } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 7a0bf0cacdfb..b440208e3e32 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -20,6 +20,8 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import static android.os.IServiceManager.DUMP_FLAG_PROTO; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static android.provider.Settings.Secure.STYLUS_HANDWRITING_DEFAULT_VALUE; +import static android.provider.Settings.Secure.STYLUS_HANDWRITING_ENABLED; import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION; import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD; import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ATTRIBUTE; @@ -2067,10 +2069,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } synchronized (ImfLock.class) { + if (!isStylusHandwritingEnabled(mContext, userId)) { + return false; + } + + // Check if selected IME of current user supports handwriting. if (userId == mSettings.getCurrentUserId()) { return mBindingController.supportsStylusHandwriting(); } - //TODO(b/197848765): This can be optimized by caching multi-user methodMaps/methodList. //TODO(b/210039666): use cache. final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); @@ -2081,6 +2087,18 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } + private boolean isStylusHandwritingEnabled( + @NonNull Context context, @UserIdInt int userId) { + // If user is a profile, use preference of it`s parent profile. + final int profileParentUserId = mUserManagerInternal.getProfileParentId(userId); + if (Settings.Secure.getIntForUser(context.getContentResolver(), + STYLUS_HANDWRITING_ENABLED, STYLUS_HANDWRITING_DEFAULT_VALUE, + profileParentUserId) == 0) { + return false; + } + return true; + } + @GuardedBy("ImfLock.class") private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId, @DirectBootAwareness int directBootAwareness, int callingUid) { @@ -3418,8 +3436,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void prepareStylusHandwritingDelegation( @NonNull IInputMethodClient client, + @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName) { + if (!isStylusHandwritingEnabled(mContext, userId)) { + Slog.w(TAG, "Can not prepare stylus handwriting delegation. Stylus handwriting" + + " pref is disabled for user: " + userId); + return; + } if (!verifyClientAndPackageMatch(client, delegatorPackageName)) { Slog.w(TAG, "prepareStylusHandwritingDelegation() fail"); throw new IllegalArgumentException("Delegator doesn't match Uid"); @@ -3430,8 +3454,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public boolean acceptStylusHandwritingDelegation( @NonNull IInputMethodClient client, + @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName) { + if (!isStylusHandwritingEnabled(mContext, userId)) { + Slog.w(TAG, "Can not accept stylus handwriting delegation. Stylus handwriting" + + " pref is disabled for user: " + userId); + return false; + } if (!verifyDelegator(client, delegatePackageName, delegatorPackageName)) { return false; } diff --git a/services/core/java/com/android/server/locales/AppLocaleChangedAtomRecord.java b/services/core/java/com/android/server/locales/AppLocaleChangedAtomRecord.java index 2be2ef8c35af..7a70db22106e 100644 --- a/services/core/java/com/android/server/locales/AppLocaleChangedAtomRecord.java +++ b/services/core/java/com/android/server/locales/AppLocaleChangedAtomRecord.java @@ -20,24 +20,32 @@ import static android.os.Process.INVALID_UID; import com.android.internal.util.FrameworkStatsLog; +import java.util.Locale; + /** * Holds data used to report the ApplicationLocalesChanged atom. */ public final class AppLocaleChangedAtomRecord { + private static final String DEFAULT_PREFIX = "default-"; final int mCallingUid; int mTargetUid = INVALID_UID; - String mNewLocales = ""; - String mPrevLocales = ""; + String mNewLocales = DEFAULT_PREFIX; + String mPrevLocales = DEFAULT_PREFIX; int mStatus = FrameworkStatsLog .APPLICATION_LOCALES_CHANGED__STATUS__STATUS_UNSPECIFIED; int mCaller = FrameworkStatsLog .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_UNKNOWN; AppLocaleChangedAtomRecord(int callingUid) { this.mCallingUid = callingUid; + Locale defaultLocale = Locale.getDefault(); + if (defaultLocale != null) { + this.mNewLocales = DEFAULT_PREFIX + defaultLocale.toLanguageTag(); + this.mPrevLocales = DEFAULT_PREFIX + defaultLocale.toLanguageTag(); + } } void setNewLocales(String newLocales) { - this.mNewLocales = newLocales; + this.mNewLocales = convertEmptyLocales(newLocales); } void setTargetUid(int targetUid) { @@ -45,7 +53,7 @@ public final class AppLocaleChangedAtomRecord { } void setPrevLocales(String prevLocales) { - this.mPrevLocales = prevLocales; + this.mPrevLocales = convertEmptyLocales(prevLocales); } void setStatus(int status) { @@ -55,4 +63,16 @@ public final class AppLocaleChangedAtomRecord { void setCaller(int caller) { this.mCaller = caller; } + + private String convertEmptyLocales(String locales) { + String target = locales; + if ("".equals(locales)) { + Locale defaultLocale = Locale.getDefault(); + if (defaultLocale != null) { + target = DEFAULT_PREFIX + defaultLocale.toLanguageTag(); + } + } + + return target; + } } diff --git a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java index 6cd2ed41e94c..0049213cbf55 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java +++ b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java @@ -44,6 +44,7 @@ import android.util.SparseArray; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -377,7 +378,8 @@ class LocaleManagerBackupHelper { // Restore the locale immediately try { mLocaleManagerService.setApplicationLocales(pkgName, userId, - LocaleList.forLanguageTags(localesInfo.mLocales), localesInfo.mSetFromDelegate); + LocaleList.forLanguageTags(localesInfo.mLocales), localesInfo.mSetFromDelegate, + FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); if (DEBUG) { Slog.d(TAG, "Restored locales=" + localesInfo.mLocales + " fromDelegate=" + localesInfo.mSetFromDelegate + " for package=" + pkgName); @@ -662,7 +664,9 @@ class LocaleManagerBackupHelper { try { LocaleConfig localeConfig = new LocaleConfig( mContext.createPackageContextAsUser(packageName, 0, UserHandle.of(userId))); - mLocaleManagerService.removeUnsupportedAppLocales(packageName, userId, localeConfig); + mLocaleManagerService.removeUnsupportedAppLocales(packageName, userId, localeConfig, + FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APP_UPDATE_LOCALES_CHANGE); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Can not found the package name : " + packageName + " / " + e); } diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java index e3a555bd2f6a..43e346a5bfa3 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerService.java +++ b/services/core/java/com/android/server/locales/LocaleManagerService.java @@ -182,8 +182,11 @@ public class LocaleManagerService extends SystemService { @Override public void setApplicationLocales(@NonNull String appPackageName, @UserIdInt int userId, @NonNull LocaleList locales, boolean fromDelegate) throws RemoteException { + int caller = fromDelegate + ? FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DELEGATE + : FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS; LocaleManagerService.this.setApplicationLocales(appPackageName, userId, locales, - fromDelegate); + fromDelegate, caller); } @Override @@ -226,13 +229,14 @@ public class LocaleManagerService extends SystemService { * Sets the current UI locales for a specified app. */ public void setApplicationLocales(@NonNull String appPackageName, @UserIdInt int userId, - @NonNull LocaleList locales, boolean fromDelegate) + @NonNull LocaleList locales, boolean fromDelegate, int caller) throws RemoteException, IllegalArgumentException { AppLocaleChangedAtomRecord atomRecordForMetrics = new AppLocaleChangedAtomRecord(Binder.getCallingUid()); try { requireNonNull(appPackageName); requireNonNull(locales); + atomRecordForMetrics.setCaller(caller); atomRecordForMetrics.setNewLocales(locales.toLanguageTags()); //Allow apps with INTERACT_ACROSS_USERS permission to set locales for different user. userId = mActivityManagerInternal.handleIncomingUser( @@ -273,8 +277,8 @@ public class LocaleManagerService extends SystemService { + " and user " + userId); } - atomRecordForMetrics.setPrevLocales(getApplicationLocalesUnchecked(appPackageName, userId) - .toLanguageTags()); + atomRecordForMetrics.setPrevLocales( + getApplicationLocalesUnchecked(appPackageName, userId).toLanguageTags()); final ActivityTaskManagerInternal.PackageConfigurationUpdater updater = mActivityTaskManagerInternal.createPackageConfigurationUpdater(appPackageName, userId); @@ -619,7 +623,10 @@ public class LocaleManagerService extends SystemService { Slog.d(TAG, "remove the override LocaleConfig"); file.delete(); } - removeUnsupportedAppLocales(appPackageName, userId, resLocaleConfig); + removeUnsupportedAppLocales(appPackageName, userId, resLocaleConfig, + FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DYNAMIC_LOCALES_CHANGE + ); atomRecord.setOverrideRemoved(true); atomRecord.setStatus(FrameworkStatsLog .APP_SUPPORTED_LOCALES_CHANGED__STATUS__SUCCESS); @@ -661,7 +668,10 @@ public class LocaleManagerService extends SystemService { } atomicFile.finishWrite(stream); // Clear per-app locales if they are not in the override LocaleConfig. - removeUnsupportedAppLocales(appPackageName, userId, overrideLocaleConfig); + removeUnsupportedAppLocales(appPackageName, userId, overrideLocaleConfig, + FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DYNAMIC_LOCALES_CHANGE + ); if (overrideLocaleConfig.isSameLocaleConfig(resLocaleConfig)) { Slog.d(TAG, "setOverrideLocaleConfig, same as the app's LocaleConfig"); atomRecord.setSameAsResConfig(true); @@ -678,9 +688,12 @@ public class LocaleManagerService extends SystemService { /** * Checks if the per-app locales are in the LocaleConfig. Per-app locales missing from the * LocaleConfig will be removed. + * + * <p><b>Note:</b> Check whether to remove the per-app locales when the app is upgraded or + * the LocaleConfig is overridden. */ void removeUnsupportedAppLocales(String appPackageName, int userId, - LocaleConfig localeConfig) { + LocaleConfig localeConfig, int caller) { LocaleList appLocales = getApplicationLocalesUnchecked(appPackageName, userId); // Remove the per-app locales from the locale list if they don't exist in the LocaleConfig. boolean resetAppLocales = false; @@ -707,7 +720,7 @@ public class LocaleManagerService extends SystemService { try { setApplicationLocales(appPackageName, userId, new LocaleList(newAppLocales.toArray(locales)), - mBackupHelper.areLocalesSetFromDelegate(userId, appPackageName)); + mBackupHelper.areLocalesSetFromDelegate(userId, appPackageName), caller); } catch (RemoteException | IllegalArgumentException e) { Slog.e(TAG, "Could not set locales for " + appPackageName, e); } diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index e48412ab4029..82b4da3850f4 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -103,6 +103,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; +import android.util.Pair; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; @@ -1396,11 +1397,14 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.v(TAG, "SV count: " + gnssStatus.getSatelliteCount()); } + Set<Pair<Integer, Integer>> satellites = new HashSet<>(); int usedInFixCount = 0; int maxCn0 = 0; int meanCn0 = 0; for (int i = 0; i < gnssStatus.getSatelliteCount(); i++) { if (gnssStatus.usedInFix(i)) { + satellites.add( + new Pair<>(gnssStatus.getConstellationType(i), gnssStatus.getSvid(i))); ++usedInFixCount; if (gnssStatus.getCn0DbHz(i) > maxCn0) { maxCn0 = (int) gnssStatus.getCn0DbHz(i); @@ -1413,7 +1417,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements meanCn0 /= usedInFixCount; } // return number of sats used in fix instead of total reported - mLocationExtras.set(usedInFixCount, meanCn0, maxCn0); + mLocationExtras.set(satellites.size(), meanCn0, maxCn0); mGnssMetrics.logSvStatus(gnssStatus); } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 16155a01d73a..5ea2ca4fc2f2 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -17,6 +17,8 @@ package com.android.server.media; import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; @@ -55,6 +57,8 @@ import android.util.EventLog; import android.util.Log; import android.view.KeyEvent; +import com.android.server.LocalServices; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -422,6 +426,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR */ @Override public void close() { + // Log the session's active state + // to measure usage of foreground service resources + int callingUid = Binder.getCallingUid(); + int callingPid = Binder.getCallingPid(); + LocalServices.getService(ActivityManagerInternal.class) + .logFgsApiEnd(ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK, + callingUid, callingPid); synchronized (mLock) { if (mDestroyed) { return; @@ -884,8 +895,22 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR @Override public void setActive(boolean active) throws RemoteException { + // Log the session's active state + // to measure usage of foreground service resources + int callingUid = Binder.getCallingUid(); + int callingPid = Binder.getCallingPid(); + if (active) { + LocalServices.getService(ActivityManagerInternal.class) + .logFgsApiBegin(ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK, + callingUid, callingPid); + } else { + LocalServices.getService(ActivityManagerInternal.class) + .logFgsApiEnd(ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK, + callingUid, callingPid); + } + mIsActive = active; - final long token = Binder.clearCallingIdentity(); + long token = Binder.clearCallingIdentity(); try { mService.onSessionActiveStateChanged(MediaSessionRecord.this); } finally { diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index b75b7d4daacd..48acc7c2ba8d 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -16,6 +16,7 @@ package com.android.server.media.projection; +import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION; import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED; import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED; @@ -282,7 +283,7 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call public IMediaProjection createProjection(int uid, String packageName, int type, boolean isPermanentGrant) { - if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION) + if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to grant " + "projection permission"); @@ -314,16 +315,21 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call public boolean isCurrentProjection(IMediaProjection projection) { + if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to check " + + "if the given projection is current."); + } return MediaProjectionManagerService.this.isCurrentProjection( projection == null ? null : projection.asBinder()); } @Override // Binder call public MediaProjectionInfo getActiveProjectionInfo() { - if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION) + if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add " - + "projection callbacks"); + throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to get " + + "active projection info"); } final long token = Binder.clearCallingIdentity(); try { @@ -335,10 +341,10 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call public void stopActiveProjection() { - if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION) + if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add " - + "projection callbacks"); + throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to stop " + + "the active projection"); } final long token = Binder.clearCallingIdentity(); try { @@ -352,7 +358,7 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call public void notifyActiveProjectionCapturedContentResized(int width, int height) { - if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION) + if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to notify " + "on captured content resize"); @@ -372,10 +378,10 @@ public final class MediaProjectionManagerService extends SystemService @Override public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) { - if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION) + if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to notify " - + "on captured content resize"); + + "on captured content visibility changed"); } if (!isCurrentProjection(mProjectionGrant)) { return; @@ -392,7 +398,7 @@ public final class MediaProjectionManagerService extends SystemService @Override //Binder call public void addCallback(final IMediaProjectionWatcherCallback callback) { - if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION) + if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add " + "projection callbacks"); @@ -407,7 +413,7 @@ public final class MediaProjectionManagerService extends SystemService @Override public void removeCallback(IMediaProjectionWatcherCallback callback) { - if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION) + if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to remove " + "projection callbacks"); @@ -512,6 +518,11 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call public int applyVirtualDisplayFlags(int flags) { + if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION to apply virtual " + + "display flags."); + } if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) { flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR @@ -660,11 +671,21 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call public void setLaunchCookie(IBinder launchCookie) { + if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION to set launch " + + "cookie."); + } mLaunchCookie = launchCookie; } @Override // Binder call public IBinder getLaunchCookie() { + if (mContext.checkCallingOrSelfPermission(MANAGE_MEDIA_PROJECTION) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION to get launch " + + "cookie."); + } return mLaunchCookie; } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 92be0943c9f4..4c36b910e77b 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -5550,7 +5550,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Do this without the lock held. handleUidChanged() and handleUidGone() are // called from the handler, so there's no multi-threading issue. if (updated) { - updateNetworkStats(uid, isProcStateAllowedWhileOnRestrictBackground(procState)); + updateNetworkStats(uid, + isProcStateAllowedWhileOnRestrictBackground(procState, capability)); } } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java index a561390ac7e4..d3dea0d96812 100644 --- a/services/core/java/com/android/server/notification/BubbleExtractor.java +++ b/services/core/java/com/android/server/notification/BubbleExtractor.java @@ -182,7 +182,7 @@ public class BubbleExtractor implements NotificationSignalExtractor { /** * Whether an intent is properly configured to display in an {@link - * com.android.wm.shell.TaskView} for bubbling. + * TaskView} for bubbling. * * @param context the context to use. * @param pendingIntent the pending intent of the bubble. diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f09f7c2797e5..65dcec702ef4 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -265,6 +265,7 @@ import android.util.SparseBooleanArray; import android.util.StatsEvent; import android.util.Xml; import android.util.proto.ProtoOutputStream; +import android.view.Display; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.RemoteViews; @@ -316,6 +317,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.UriGrantsManagerInternal; +import com.android.server.utils.Slogf; import com.android.server.utils.quota.MultiRateLimiter; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.BackgroundActivityStartCallback; @@ -3288,19 +3290,22 @@ public class NotificationManagerService extends SystemService { @Override public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, - int displayId, @Nullable ITransientNotificationCallback callback) { - enqueueToast(pkg, token, text, null, duration, displayId, callback); + boolean isUiContext, int displayId, + @Nullable ITransientNotificationCallback textCallback) { + enqueueToast(pkg, token, text, /* callback= */ null, duration, isUiContext, displayId, + textCallback); } @Override public void enqueueToast(String pkg, IBinder token, ITransientNotification callback, - int duration, int displayId) { - enqueueToast(pkg, token, null, callback, duration, displayId, null); + int duration, boolean isUiContext, int displayId) { + enqueueToast(pkg, token, /* text= */ null, callback, duration, isUiContext, displayId, + /* textCallback= */ null); } private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text, - @Nullable ITransientNotification callback, int duration, int displayId, - @Nullable ITransientNotificationCallback textCallback) { + @Nullable ITransientNotification callback, int duration, boolean isUiContext, + int displayId, @Nullable ITransientNotificationCallback textCallback) { if (DBG) { Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token + " duration=" + duration + " displayId=" + displayId); @@ -3318,10 +3323,27 @@ public class NotificationManagerService extends SystemService { final boolean isSystemToast = isCallerSystemOrPhone() || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); boolean isAppRenderedToast = (callback != null); - if (!checkCanEnqueueToast(pkg, callingUid, isAppRenderedToast, isSystemToast)) { + if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast, + isSystemToast)) { return; } + if (!isUiContext && displayId == Display.DEFAULT_DISPLAY + && mUm.isVisibleBackgroundUsersSupported()) { + // When the caller is a visible background user using a non-UI context (like the + // application context), the Toast must be displayed in the display the user was + // started visible on. + int userId = UserHandle.getUserId(callingUid); + int userDisplayId = mUmInternal.getMainDisplayAssignedToUser(userId); + if (displayId != userDisplayId) { + if (DBG) { + Slogf.d(TAG, "Changing display id from %d to %d on user %d", displayId, + userDisplayId, userId); + } + displayId = userDisplayId; + } + } + synchronized (mToastQueue) { int callingPid = Binder.getCallingPid(); final long callingId = Binder.clearCallingIdentity(); @@ -3372,7 +3394,7 @@ public class NotificationManagerService extends SystemService { } } - private boolean checkCanEnqueueToast(String pkg, int callingUid, + private boolean checkCanEnqueueToast(String pkg, int callingUid, int displayId, boolean isAppRenderedToast, boolean isSystemToast) { final boolean isPackageSuspended = isPackagePaused(pkg); final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, @@ -3402,6 +3424,13 @@ public class NotificationManagerService extends SystemService { return false; } + int userId = UserHandle.getUserId(callingUid); + if (!isSystemToast && !mUmInternal.isUserVisible(userId, displayId)) { + Slog.e(TAG, "Suppressing toast from package " + pkg + "/" + callingUid + " as user " + + userId + " is not visible on display " + displayId); + return false; + } + return true; } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 1cfcb4ea3a7e..c9a6c630d41b 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -545,6 +545,7 @@ public final class NotificationRecord { pw.println(prefix + "mAdjustments=" + mAdjustments); pw.println(prefix + "shortcut=" + notification.getShortcutId() + " found valid? " + (mShortcutInfo != null)); + pw.println(prefix + "mUserVisOverride=" + getPackageVisibilityOverride()); } private void dumpNotification(PrintWriter pw, String prefix, Notification notification, @@ -574,6 +575,7 @@ public final class NotificationRecord { } else { pw.println("null"); } + pw.println(prefix + "vis=" + notification.visibility); pw.println(prefix + "contentView=" + formatRemoteViews(notification.contentView)); pw.println(prefix + "bigContentView=" + formatRemoteViews(notification.bigContentView)); pw.println(prefix + "headsUpContentView=" diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index aa97aa3655e2..f733199d9967 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -2045,9 +2045,10 @@ public class PreferencesHelper implements RankingConfig { // before the migration is enabled, this will simply default to false in all cases. boolean importanceIsUserSet = false; // Even if this package's data is not present, we need to write something; - // so default to IMPORTANCE_NONE, since if PM doesn't know about the package - // for some reason, notifications are not allowed. - int importance = IMPORTANCE_NONE; + // default to IMPORTANCE_UNSPECIFIED. If PM doesn't know about the package + // for some reason, notifications are not allowed, but in logged output we want + // to distinguish this case from the actually-banned packages. + int importance = IMPORTANCE_UNSPECIFIED; Pair<Integer, String> key = new Pair<>(r.uid, r.pkg); if (pkgPermissions != null && pkgsWithPermissionsToHandle.contains(key)) { Pair<Boolean, Boolean> permissionPair = pkgPermissions.get(key); diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java index e698c4b5b3f1..060534507c5d 100644 --- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java +++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java @@ -39,14 +39,18 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.LocalLog; import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DumpUtils; import com.android.server.SystemConfig; +import com.android.server.utils.Slogf; import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Objects; import java.util.OptionalInt; @@ -56,7 +60,11 @@ import java.util.OptionalInt; * <p>Delegates the actualy generation to a native implementation of {@code IDumpstate}. */ class BugreportManagerServiceImpl extends IDumpstate.Stub { + + private static final int LOCAL_LOG_SIZE = 20; private static final String TAG = "BugreportManagerService"; + private static final boolean DEBUG = false; + private static final String BUGREPORT_SERVICE = "bugreportd"; private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000; @@ -64,12 +72,22 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { private final Context mContext; private final AppOpsManager mAppOps; private final TelephonyManager mTelephonyManager; - private final ArraySet<String> mBugreportWhitelistedPackages; + private final ArraySet<String> mBugreportAllowlistedPackages; private final BugreportFileManager mBugreportFileManager; + @GuardedBy("mLock") private OptionalInt mPreDumpedDataUid = OptionalInt.empty(); + // Attributes below are just Used for dump() purposes + @Nullable + @GuardedBy("mLock") + private DumpstateListener mCurrentDumpstateListener; + @GuardedBy("mLock") + private int mNumberFinishedBugreports; + @GuardedBy("mLock") + private final LocalLog mFinishedBugreports = new LocalLog(LOCAL_LOG_SIZE); + /** Helper class for associating previously generated bugreports with their callers. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) static class BugreportFileManager { @@ -77,11 +95,8 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { private final Object mLock = new Object(); @GuardedBy("mLock") - private final ArrayMap<Pair<Integer, String>, ArraySet<String>> mBugreportFiles; - - BugreportFileManager() { - mBugreportFiles = new ArrayMap<>(); - } + private final ArrayMap<Pair<Integer, String>, ArraySet<String>> mBugreportFiles = + new ArrayMap<>(); /** * Checks that a given file was generated on behalf of the given caller. If the file was @@ -159,11 +174,9 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { mAppOps = mContext.getSystemService(AppOpsManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mBugreportFileManager = new BugreportFileManager(); - mBugreportWhitelistedPackages = - injector.getAllowlistedPackages(); + mBugreportAllowlistedPackages = injector.getAllowlistedPackages(); } - @Override @RequiresPermission(android.Manifest.permission.DUMP) public void preDumpUiData(String callingPackage) { @@ -196,6 +209,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { Binder.restoreCallingIdentity(identity); } + Slogf.i(TAG, "Starting bugreport for %s / %d", callingPackage, callingUid); synchronized (mLock) { startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode, bugreportFlags, listener, isScreenshotRequested); @@ -208,6 +222,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { int callingUid = Binder.getCallingUid(); enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */); + Slogf.i(TAG, "Cancelling bugreport for %s / %d", callingPackage, callingUid); synchronized (mLock) { IDumpstate ds = getDumpstateBinderServiceLocked(); if (ds == null) { @@ -234,6 +249,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { int callingUid = Binder.getCallingUid(); enforcePermission(callingPackage, callingUid, false); + Slogf.i(TAG, "Retrieving bugreport for %s / %d", callingPackage, callingUid); try { mBugreportFileManager.ensureCallerPreviouslyGeneratedFile( new Pair<>(callingUid, callingPackage), bugreportFile); @@ -260,8 +276,9 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } // Wrap the listener so we can intercept binder events directly. - IDumpstateListener myListener = new DumpstateListener(listener, ds, - new Pair<>(callingUid, callingPackage)); + DumpstateListener myListener = new DumpstateListener(listener, ds, + new Pair<>(callingUid, callingPackage), /* reportFinishedFile= */ true); + setCurrentDumpstateListenerLocked(myListener); try { ds.retrieveBugreport(callingUid, callingPackage, bugreportFd, bugreportFile, myListener); @@ -271,6 +288,16 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } } + @GuardedBy("mLock") + private void setCurrentDumpstateListenerLocked(DumpstateListener listener) { + if (mCurrentDumpstateListener != null) { + Slogf.w(TAG, "setCurrentDumpstateListenerLocked(%s): called when " + + "mCurrentDumpstateListener is already set (%s)", listener, + mCurrentDumpstateListener); + } + mCurrentDumpstateListener = listener; + } + private void validateBugreportMode(@BugreportParams.BugreportMode int mode) { if (mode != BugreportParams.BUGREPORT_MODE_FULL && mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE @@ -299,7 +326,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { // To gain access through the DUMP permission, the OEM has to allow this package explicitly // via sysconfig and privileged permissions. - if (mBugreportWhitelistedPackages.contains(callingPackage) + if (mBugreportAllowlistedPackages.contains(callingPackage) && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) == PackageManager.PERMISSION_GRANTED) { return; @@ -436,7 +463,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } } - boolean isConsentDeferred = + boolean reportFinishedFile = (bugreportFlags & BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT) != 0; IDumpstate ds = startAndGetDumpstateBinderServiceLocked(); @@ -446,9 +473,9 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { return; } - // Wrap the listener so we can intercept binder events directly. - IDumpstateListener myListener = new DumpstateListener(listener, ds, - isConsentDeferred ? new Pair<>(callingUid, callingPackage) : null); + DumpstateListener myListener = new DumpstateListener(listener, ds, + new Pair<>(callingUid, callingPackage), reportFinishedFile); + setCurrentDumpstateListenerLocked(myListener); try { ds.startBugreport(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode, bugreportFlags, myListener, isScreenshotRequested); @@ -522,6 +549,56 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { SystemProperties.set("ctl.stop", BUGREPORT_SERVICE); } + @RequiresPermission(android.Manifest.permission.DUMP) + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + + pw.printf("Allow-listed packages: %s\n", mBugreportAllowlistedPackages); + + synchronized (mLock) { + pw.print("Pre-dumped data UID: "); + if (mPreDumpedDataUid.isEmpty()) { + pw.println("none"); + } else { + pw.println(mPreDumpedDataUid.getAsInt()); + } + + if (mCurrentDumpstateListener == null) { + pw.println("Not taking a bug report"); + } else { + mCurrentDumpstateListener.dump(pw); + } + + if (mNumberFinishedBugreports == 0) { + pw.println("No finished bugreports"); + } else { + pw.printf("%d finished bugreport%s. Last %d:\n", mNumberFinishedBugreports, + (mNumberFinishedBugreports > 1 ? "s" : ""), + Math.min(mNumberFinishedBugreports, LOCAL_LOG_SIZE)); + mFinishedBugreports.dump(" ", pw); + } + } + + synchronized (mBugreportFileManager.mLock) { + int numberFiles = mBugreportFileManager.mBugreportFiles.size(); + pw.printf("%d pending file%s", numberFiles, (numberFiles > 1 ? "s" : "")); + if (numberFiles > 0) { + for (int i = 0; i < numberFiles; i++) { + Pair<Integer, String> caller = mBugreportFileManager.mBugreportFiles.keyAt(i); + ArraySet<String> files = mBugreportFileManager.mBugreportFiles.valueAt(i); + pw.printf(" %s: %s\n", callerToString(caller), files); + } + } else { + pw.println(); + } + } + } + + private static String callerToString(@Nullable Pair<Integer, String> caller) { + return (caller == null) ? "N/A" : caller.second + "/" + caller.first; + } + private int clearBugreportFlag(int flags, @BugreportParams.BugreportFlag int flag) { flags &= ~flag; return flags; @@ -541,19 +618,28 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { throw new IllegalArgumentException(message); } - private final class DumpstateListener extends IDumpstateListener.Stub implements DeathRecipient { + + private static int sNextId; + + private final int mId = ++sNextId; // used for debugging purposes only private final IDumpstateListener mListener; private final IDumpstate mDs; - private boolean mDone = false; private final Pair<Integer, String> mCaller; + private final boolean mReportFinishedFile; + private int mProgress; // used for debugging purposes only + private boolean mDone; DumpstateListener(IDumpstateListener listener, IDumpstate ds, - @Nullable Pair<Integer, String> caller) { + Pair<Integer, String> caller, boolean reportFinishedFile) { + if (DEBUG) { + Slogf.d(TAG, "Starting DumpstateListener(id=%d) for caller %s", mId, caller); + } mListener = listener; mDs = ds; mCaller = caller; + mReportFinishedFile = reportFinishedFile; try { mDs.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { @@ -563,35 +649,51 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { @Override public void onProgress(int progress) throws RemoteException { + if (DEBUG) { + Slogf.d(TAG, "onProgress: %d", progress); + } + mProgress = progress; mListener.onProgress(progress); } @Override public void onError(int errorCode) throws RemoteException { + Slogf.e(TAG, "onError(): %d", errorCode); synchronized (mLock) { - mDone = true; + releaseItselfLocked(); + reportFinishedLocked("ErroCode: " + errorCode); } mListener.onError(errorCode); } @Override public void onFinished(String bugreportFile) throws RemoteException { + Slogf.i(TAG, "onFinished(): %s", bugreportFile); synchronized (mLock) { - mDone = true; + releaseItselfLocked(); + reportFinishedLocked("File: " + bugreportFile); } - if (mCaller != null) { + if (mReportFinishedFile) { mBugreportFileManager.addBugreportFileForCaller(mCaller, bugreportFile); + } else if (DEBUG) { + Slog.d(TAG, "Not reporting finished file"); } mListener.onFinished(bugreportFile); } @Override public void onScreenshotTaken(boolean success) throws RemoteException { + if (DEBUG) { + Slogf.d(TAG, "onScreenshotTaken(): %b", success); + } mListener.onScreenshotTaken(success); } @Override public void onUiIntensiveBugreportDumpsFinished() throws RemoteException { + if (DEBUG) { + Slogf.d(TAG, "onUiIntensiveBugreportDumpsFinished()"); + } mListener.onUiIntensiveBugreportDumpsFinished(); } @@ -617,5 +719,39 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } mDs.asBinder().unlinkToDeath(this, 0); } + + @Override + public String toString() { + return "DumpstateListener[id=" + mId + ", progress=" + mProgress + "]"; + } + + @GuardedBy("mLock") + private void reportFinishedLocked(String message) { + mNumberFinishedBugreports++; + mFinishedBugreports.log("Caller: " + callerToString(mCaller) + " " + message); + } + + private void dump(PrintWriter pw) { + pw.println("DumpstateListener:"); + pw.printf(" id: %d\n", mId); + pw.printf(" caller: %s\n", callerToString(mCaller)); + pw.printf(" reports finished file: %b\n", mReportFinishedFile); + pw.printf(" progress: %d\n", mProgress); + pw.printf(" done: %b\n", mDone); + } + + @GuardedBy("mLock") + private void releaseItselfLocked() { + mDone = true; + if (mCurrentDumpstateListener == this) { + if (DEBUG) { + Slogf.d(TAG, "releaseItselfLocked(): releasing %s", this); + } + mCurrentDumpstateListener = null; + } else { + Slogf.w(TAG, "releaseItselfLocked(): " + this + " is finished, but current listener" + + " is " + mCurrentDumpstateListener); + } + } } } diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index acd4a96c2817..6f7ce80e42b1 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -571,6 +571,7 @@ public class ComputerEngine implements Computer { if (!blockInstantResolution && !blockNormalResolution) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; + ri.userHandle = UserHandle.of(userId); list = new ArrayList<>(1); list.add(ri); PackageManagerServiceUtils.applyEnforceIntentFilterMatching( diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 77e4688cecb5..42538f33c5f8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -42,7 +42,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; +import android.compat.annotation.Disabled; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -189,7 +189,7 @@ public class PackageManagerServiceUtils { * allow 3P apps to trigger internal-only functionality. */ @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + @Disabled /* Revert enforcement: b/274147456 */ private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188; /** diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 02d13bcbb8ae..417ba0729066 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2217,10 +2217,10 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile } if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) { serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState()); - if (ustate.getLastDisableAppCaller() != null) { - serializer.attribute(null, ATTR_ENABLED_CALLER, - ustate.getLastDisableAppCaller()); - } + } + if (ustate.getLastDisableAppCaller() != null) { + serializer.attribute(null, ATTR_ENABLED_CALLER, + ustate.getLastDisableAppCaller()); } if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) { serializer.attributeInt(null, ATTR_INSTALL_REASON, diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java index b4b8cb2a370d..ad77ef7ca975 100644 --- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java +++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java @@ -28,6 +28,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; +import android.app.BroadcastOptions; import android.app.IActivityManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.Intent; @@ -620,12 +621,15 @@ public final class SuspendPackageHelper { extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList); extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList); final int flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND; + final Bundle options = new BroadcastOptions() + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) + .toBundle(); handler.post(() -> mBroadcastHelper.sendPackageBroadcast(intent, null /* pkg */, extras, flags, null /* targetPkg */, null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */, null /* broadcastAllowList */, (callingUid, intentExtras) -> BroadcastHelper.filterExtrasChangedPackageList( mPm.snapshotComputer(), callingUid, intentExtras), - null /* bOptions */)); + options)); } /** diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index a36e9f961211..927a722defac 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1276,7 +1276,15 @@ public class UserManagerService extends IUserManager.Stub { getDevicePolicyManagerInternal().broadcastIntentToManifestReceivers( intent, parentHandle, /* requiresPermission= */ true); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); - mContext.sendBroadcastAsUser(intent, parentHandle); + final Bundle options = new BroadcastOptions() + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) + .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) + // Both actions use single namespace because only the final state matters. + .setDeliveryGroupMatchingKey( + Intent.ACTION_MANAGED_PROFILE_AVAILABLE /* namespace */, + String.valueOf(profileHandle.getIdentifier()) /* key */) + .toBundle(); + mContext.sendBroadcastAsUser(intent, parentHandle, /* receiverPermission= */ null, options); } @Override diff --git a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java index 333c98c4818d..835ab6a8e8bc 100644 --- a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java +++ b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java @@ -530,10 +530,10 @@ public class UserManagerServiceShellCommand extends ShellCommand { PrintWriter pw = getOutPrintWriter(); final int mainUserId = mService.getMainUserId(); if (mainUserId == UserHandle.USER_NULL) { - pw.println("Couldn't get main user."); + pw.println("None"); return 1; } - pw.println("Main user id: " + mainUserId); + pw.println(mainUserId); return 0; } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index b32e8f0b3221..54f87d004b5c 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -590,7 +590,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int mDoubleTapOnHomeBehavior; // Whether to lock the device after the next app transition has finished. - private boolean mLockAfterAppTransitionFinished; + boolean mLockAfterAppTransitionFinished; // Allowed theater mode wake actions private boolean mAllowTheaterModeWakeFromKey; @@ -3259,6 +3259,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in" + " interceptKeyBeforeQueueing"); return key_consumed; + case KeyEvent.KEYCODE_MACRO_1: + case KeyEvent.KEYCODE_MACRO_2: + case KeyEvent.KEYCODE_MACRO_3: + case KeyEvent.KEYCODE_MACRO_4: + Slog.wtf(TAG, "KEYCODE_MACRO_x should be handled in interceptKeyBeforeQueueing"); + return key_consumed; } if (isValidGlobalKey(keyCode) @@ -4396,6 +4402,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { result &= ~ACTION_PASS_TO_USER; break; } + case KeyEvent.KEYCODE_MACRO_1: + case KeyEvent.KEYCODE_MACRO_2: + case KeyEvent.KEYCODE_MACRO_3: + case KeyEvent.KEYCODE_MACRO_4: + // TODO(b/266098478): Add logic to handle KEYCODE_MACROx feature + result &= ~ACTION_PASS_TO_USER; + break; } if (useHapticFeedback) { diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java index 135841729e69..2638f34fe7df 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsService.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java @@ -360,7 +360,7 @@ public class PowerStatsService extends SystemService { sb.append("ALL"); } sb.append("["); - for (int i = 0; i < expectedLength; i++) { + for (int i = 0; i < energyConsumerIds.length; i++) { final int id = energyConsumerIds[i]; sb.append(id); sb.append("(type:"); diff --git a/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java index f653e4b26438..6cb6dc07f8b8 100644 --- a/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java +++ b/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java @@ -28,7 +28,8 @@ public final class ProcfsMemoryUtil { "VmHWM:", "VmRSS:", "RssAnon:", - "VmSwap:" + "RssShmem:", + "VmSwap:", }; private static final String[] VMSTAT_KEYS = new String[] { "oom_kill" @@ -38,7 +39,7 @@ public final class ProcfsMemoryUtil { /** * Reads memory stats of a process from procfs. Returns values of the VmHWM, VmRss, AnonRSS, - * VmSwap fields in /proc/pid/status in kilobytes or null if not available. + * VmSwap, RssShmem fields in /proc/pid/status in kilobytes or null if not available. */ @Nullable public static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { @@ -46,8 +47,9 @@ public final class ProcfsMemoryUtil { output[0] = -1; output[3] = -1; output[4] = -1; + output[5] = -1; Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output); - if (output[0] == -1 || output[3] == -1 || output[4] == -1) { + if (output[0] == -1 || output[3] == -1 || output[4] == -1 || output[5] == -1) { // Could not open or parse file. return null; } @@ -56,7 +58,8 @@ public final class ProcfsMemoryUtil { snapshot.rssHighWaterMarkInKilobytes = (int) output[1]; snapshot.rssInKilobytes = (int) output[2]; snapshot.anonRssInKilobytes = (int) output[3]; - snapshot.swapInKilobytes = (int) output[4]; + snapshot.rssShmemKilobytes = (int) output[4]; + snapshot.swapInKilobytes = (int) output[5]; return snapshot; } @@ -101,6 +104,7 @@ public final class ProcfsMemoryUtil { public int rssInKilobytes; public int anonRssInKilobytes; public int swapInKilobytes; + public int rssShmemKilobytes; } /** Reads and parses selected entries of /proc/vmstat. */ 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 f8a4b04180c3..b2f48d9e3d8c 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -2290,7 +2290,8 @@ public class StatsPullAtomService extends SystemService { managedProcess.processName, managedProcess.pid, managedProcess.oomScore, snapshot.rssInKilobytes, snapshot.anonRssInKilobytes, snapshot.swapInKilobytes, snapshot.anonRssInKilobytes + snapshot.swapInKilobytes, - gpuMemPerPid.get(managedProcess.pid), managedProcess.hasForegroundServices)); + gpuMemPerPid.get(managedProcess.pid), managedProcess.hasForegroundServices, + snapshot.rssShmemKilobytes)); } // Complement the data with native system processes. Given these measurements can be taken // in response to LMKs happening, we want to first collect the managed app stats (to @@ -2309,7 +2310,8 @@ public class StatsPullAtomService extends SystemService { -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/, snapshot.rssInKilobytes, snapshot.anonRssInKilobytes, snapshot.swapInKilobytes, snapshot.anonRssInKilobytes + snapshot.swapInKilobytes, - gpuMemPerPid.get(pid), false /* has_foreground_services */)); + gpuMemPerPid.get(pid), false /* has_foreground_services */, + snapshot.rssShmemKilobytes)); } return StatsManager.PULL_SUCCESS; } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 88d64df99d48..35e88c1a2485 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -33,6 +33,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.TestApi; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityThread; @@ -178,6 +179,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private final SessionMonitor mSessionMonitor; private int mCurrentUserId; private boolean mTracingEnabled; + private int mLastSystemKey = -1; private final TileRequestTracker mTileRequestTracker; @@ -905,6 +907,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D return; } + mLastSystemKey = key; + if (mBar != null) { try { mBar.handleSystemKey(key); @@ -914,6 +918,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override + @TestApi + public int getLastSystemKey() { + enforceStatusBar(); + + return mLastSystemKey; + } + + @Override public void showPinningEnterExitToast(boolean entering) throws RemoteException { if (mBar != null) { try { diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 2141eba3be50..7f129ea3801c 100644 --- a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -171,6 +171,18 @@ class NetworkPriorityClassifier { return false; } + for (Map.Entry<Integer, Integer> entry : + networkPriority.getCapabilitiesMatchCriteria().entrySet()) { + final int cap = entry.getKey(); + final int matchCriteria = entry.getValue(); + + if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { + return false; + } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { + return false; + } + } + if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) { return true; } @@ -319,18 +331,6 @@ class NetworkPriorityClassifier { return false; } - for (Map.Entry<Integer, Integer> entry : - networkPriority.getCapabilitiesMatchCriteria().entrySet()) { - final int cap = entry.getKey(); - final int matchCriteria = entry.getValue(); - - if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) { - return false; - } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) { - return false; - } - } - return true; } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index f53b52c18e14..93f039d2f5b4 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -90,6 +90,7 @@ import android.os.ShellCallback; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; import android.service.wallpaper.IWallpaperConnection; import android.service.wallpaper.IWallpaperEngine; import android.service.wallpaper.IWallpaperService; @@ -2209,7 +2210,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub public ParcelFileDescriptor getWallpaperWithFeature(String callingPkg, String callingFeatureId, IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId, boolean getCropped) { - checkPermission(READ_WALLPAPER_INTERNAL); + final boolean hasPrivilege = hasPermission(READ_WALLPAPER_INTERNAL); + if (!hasPrivilege) { + mContext.getSystemService(StorageManager.class).checkPermissionReadImages(true, + Binder.getCallingPid(), Binder.getCallingUid(), callingPkg, callingFeatureId); + } + wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null); diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index f14a432f73ae..ff1c28ad1973 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -778,13 +778,12 @@ class ActivityClientController extends IActivityClientController.Stub { && r.mTransitionController.inPlayingTransition(r) && !r.mTransitionController.isCollecting() ? r.mTransitionController.createTransition(TRANSIT_TO_BACK) : null; - if (transition != null) { - r.mTransitionController.requestStartTransition(transition, null /*startTask */, - null /* remoteTransition */, null /* displayChange */); - } final boolean changed = r != null && r.setOccludesParent(true); if (transition != null) { if (changed) { + r.mTransitionController.requestStartTransition(transition, + null /*startTask */, null /* remoteTransition */, + null /* displayChange */); r.mTransitionController.setReady(r.getDisplayContent()); } else { transition.abort(); @@ -818,13 +817,12 @@ class ActivityClientController extends IActivityClientController.Stub { final Transition transition = r.mTransitionController.inPlayingTransition(r) && !r.mTransitionController.isCollecting() ? r.mTransitionController.createTransition(TRANSIT_TO_FRONT) : null; - if (transition != null) { - r.mTransitionController.requestStartTransition(transition, null /*startTask */, - null /* remoteTransition */, null /* displayChange */); - } final boolean changed = r.setOccludesParent(false); if (transition != null) { if (changed) { + r.mTransitionController.requestStartTransition(transition, + null /*startTask */, null /* remoteTransition */, + null /* displayChange */); r.mTransitionController.setReady(r.getDisplayContent()); } else { transition.abort(); diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 95fd82ff1154..a757d90b75ba 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -398,6 +398,7 @@ class ActivityMetricsLogger { /** Returns {@code true} if the incoming activity can belong to this transition. */ boolean canCoalesce(ActivityRecord r) { return mLastLaunchedActivity.mDisplayContent == r.mDisplayContent + && mLastLaunchedActivity.getTask().getBounds().equals(r.getTask().getBounds()) && mLastLaunchedActivity.getWindowingMode() == r.getWindowingMode(); } @@ -646,7 +647,7 @@ class ActivityMetricsLogger { void notifyActivityLaunched(@NonNull LaunchingState launchingState, int resultCode, boolean newActivityCreated, @Nullable ActivityRecord launchedActivity, @Nullable ActivityOptions options) { - if (launchedActivity == null) { + if (launchedActivity == null || launchedActivity.getTask() == null) { // The launch is aborted, e.g. intent not resolved, class not found. abort(launchingState, "nothing launched"); return; @@ -1154,6 +1155,8 @@ class ActivityMetricsLogger { sb.setLength(0); sb.append("Displayed "); sb.append(info.launchedActivityShortComponentName); + sb.append(" for user "); + sb.append(info.userId); sb.append(": "); TimeUtils.formatDuration(info.windowsDrawnDelayMs, sb); Log.i(TAG, sb.toString()); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 9069ac50badf..94e041aa3937 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -173,11 +173,13 @@ import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO; import static com.android.server.wm.ActivityRecordProto.NAME; import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; +import static com.android.server.wm.ActivityRecordProto.OVERRIDE_ORIENTATION; import static com.android.server.wm.ActivityRecordProto.PIP_AUTO_ENTER_ENABLED; import static com.android.server.wm.ActivityRecordProto.PROC_ID; import static com.android.server.wm.ActivityRecordProto.PROVIDES_MAX_BOUNDS; import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN; import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE; +import static com.android.server.wm.ActivityRecordProto.SHOULD_SEND_COMPAT_FAKE_FOCUS; import static com.android.server.wm.ActivityRecordProto.STARTING_DISPLAYED; import static com.android.server.wm.ActivityRecordProto.STARTING_MOVED; import static com.android.server.wm.ActivityRecordProto.STARTING_WINDOW; @@ -5265,10 +5267,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mTransitionController.collect(this); } else { inFinishingTransition = mTransitionController.inFinishingTransition(this); - if (!inFinishingTransition) { + if (!inFinishingTransition && !mDisplayContent.isSleeping()) { Slog.e(TAG, "setVisibility=" + visible + " while transition is not collecting or finishing " + this + " caller=" + Debug.getCallers(8)); + // Force showing the parents because they may be hidden by previous transition. + if (visible) { + final Transaction t = getSyncTransaction(); + for (WindowContainer<?> p = getParent(); p != null && p != mDisplayContent; + p = p.getParent()) { + if (p.mSurfaceControl != null) { + t.show(p.mSurfaceControl); + } + } + } } } } @@ -6034,6 +6046,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // An activity must be in the {@link PAUSING} state for the system to validate // the move to {@link PAUSED}. setState(PAUSING, "makeActiveIfNeeded"); + EventLogTags.writeWmPauseActivity(mUserId, System.identityHashCode(this), + shortComponentName, "userLeaving=false", "make-active"); try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, PauseActivityItem.obtain(finishing, false /* userLeaving */, @@ -10212,6 +10226,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds()); proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot); proto.write(LAST_DROP_INPUT_MODE, mLastDropInputMode); + proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation()); + proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus()); } @Override diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index f8fb76acf81e..7c1e9071b926 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -574,7 +574,9 @@ public class ActivityStartController { mService.deferWindowLayout(); try { final TransitionController controller = r.mTransitionController; - if (controller.getTransitionPlayer() != null) { + final Transition transition = controller.getCollectingTransition(); + if (transition != null) { + transition.setRemoteAnimationApp(r.app.getThread()); controller.collect(task); controller.setTransientLaunch(r, TaskDisplayArea.getRootTaskAbove(rootTask)); } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 12be1d3186a1..d4f151f5c66d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -104,6 +104,7 @@ import android.app.ProfilerInfo; import android.app.WaitResult; import android.app.WindowConfiguration; import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.compat.annotation.EnabledSince; import android.content.IIntentSender; import android.content.Intent; @@ -188,7 +189,7 @@ class ActivityStarter { * Feature flag for go/activity-security rules */ @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Disabled static final long ASM_RESTRICTIONS = 230590090L; private final ActivityTaskManagerService mService; @@ -2947,8 +2948,6 @@ class ActivityStarter { if (differentTopTask && !mAvoidMoveToFront) { mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); - // TODO(b/264487981): Consider using BackgroundActivityStartController to determine - // whether to bring the launching activity to the front. if (mSourceRecord == null || inTopNonFinishingTask(mSourceRecord)) { // We really do want to push this one into the user's face, right now. if (mLaunchTaskBehind && mSourceRecord != null) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 555cd38806e6..bbdaa24a694c 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -75,9 +75,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; -import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR; import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS; -import static com.android.server.am.ActivityManagerService.dumpStackTraces; import static com.android.server.am.ActivityManagerServiceDumpActivitiesProto.ROOT_WINDOW_CONTAINER; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONTROLLER; @@ -95,6 +93,8 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.Scr import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE; import static com.android.server.am.EventLogTags.writeBootProgressEnableScreen; import static com.android.server.am.EventLogTags.writeConfigurationChanged; +import static com.android.server.am.StackTracesDumpHelper.ANR_TRACE_DIR; +import static com.android.server.am.StackTracesDumpHelper.dumpStackTraces; import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_FIRST_ORDERED_ID; import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_LAST_ORDERED_ID; import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_FIRST_ORDERED_ID; @@ -2011,6 +2011,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } + if (r == mRootWindowContainer.getTopResumedActivity()) { + setLastResumedActivityUncheckLocked(r, "setFocusedTask-alreadyTop"); + return; + } final Transition transition = (getTransitionController().isCollecting() || !getTransitionController().isShellTransitionsEnabled()) ? null : getTransitionController().createTransition(TRANSIT_TO_FRONT); @@ -4788,11 +4792,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // until we've committed to the gesture. The focus will be transferred at the end of // the transition (if the transient launch is committed) or early if explicitly requested // via `setFocused*`. + boolean focusedAppChanged = false; if (!getTransitionController().isTransientCollect(r)) { - final Task prevFocusTask = r.mDisplayContent.mFocusedApp != null - ? r.mDisplayContent.mFocusedApp.getTask() : null; - final boolean changed = r.mDisplayContent.setFocusedApp(r); - if (changed) { + focusedAppChanged = r.mDisplayContent.setFocusedApp(r); + if (focusedAppChanged) { mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); } @@ -4801,13 +4804,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mTaskSupervisor.mRecentTasks.add(task); } - applyUpdateLockStateLocked(r); - applyUpdateVrModeLocked(r); + if (focusedAppChanged) { + applyUpdateLockStateLocked(r); + } + if (mVrController.mVrService != null) { + applyUpdateVrModeLocked(r); + } - EventLogTags.writeWmSetResumedActivity( - r == null ? -1 : r.mUserId, - r == null ? "NULL" : r.shortComponentName, - reason); + EventLogTags.writeWmSetResumedActivity(r.mUserId, r.shortComponentName, reason); } final class SleepTokenAcquirerImpl implements ActivityTaskManagerInternal.SleepTokenAcquirer { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index be503fc61c4c..feaec37fb985 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -1562,6 +1562,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } private void removePinnedRootTaskInSurfaceTransaction(Task rootTask) { + rootTask.mTransitionController.requestCloseTransitionIfNeeded(rootTask); /** * Workaround: Force-stop all the activities in the root pinned task before we reparent them * to the fullscreen root task. This is to guarantee that when we are removing a root task, diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java index bbe7a33669c8..90ec964e2f0f 100644 --- a/services/core/java/com/android/server/wm/AnrController.java +++ b/services/core/java/com/android/server/wm/AnrController.java @@ -34,7 +34,7 @@ import android.util.SparseArray; import android.view.InputApplicationHandle; import com.android.internal.os.TimeoutRecord; -import com.android.server.am.ActivityManagerService; +import com.android.server.am.StackTracesDumpHelper; import com.android.server.criticalevents.CriticalEventLog; import java.io.File; @@ -336,7 +336,7 @@ class AnrController { String criticalEvents = CriticalEventLog.getInstance().logLinesForSystemServerTraceFile(); - final File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, + final File tracesFile = StackTracesDumpHelper.dumpStackTraces(firstPids, null /* processCpuTracker */, null /* lastPids */, CompletableFuture.completedFuture(nativePids), null /* logExceptionCreatingFile */, "Pre-dump", criticalEvents, diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 841d28b0231f..597c8bf45132 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -258,7 +258,7 @@ public class AppTransitionController { tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps); if (mDisplayContent.mAtmService.mBackNavigationController .removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) { - mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(null); + mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(); } } @@ -929,7 +929,7 @@ public class AppTransitionController { /** * Returns {@code true} if a given {@link WindowContainer} is an embedded Task in - * {@link com.android.wm.shell.TaskView}. + * {@link TaskView}. * * Note that this is a short term workaround to support Android Auto until it migrate to * ShellTransition. This should only be used by {@link #getAnimationTargets}. diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index b67bc62e52f1..587e7204f993 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -32,6 +32,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.content.res.ResourceId; import android.graphics.Point; import android.graphics.Rect; @@ -61,13 +62,12 @@ import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Objects; -import java.util.function.Consumer; /** * Controller to handle actions related to the back gesture on the server side. */ class BackNavigationController { - private static final String TAG = "BackNavigationController"; + private static final String TAG = "CoreBackPreview"; private WindowManagerService mWindowManagerService; private boolean mBackAnimationInProgress; private @BackNavigationInfo.BackTargetType int mLastBackType; @@ -76,6 +76,12 @@ class BackNavigationController { private final NavigationMonitor mNavigationMonitor = new NavigationMonitor(); private AnimationHandler mAnimationHandler; + + /** + * The transition who match the back navigation targets, + * release animation after this transition finish. + */ + private Transition mWaitTransitionFinish; private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); @@ -139,6 +145,11 @@ class BackNavigationController { BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder(); synchronized (wmService.mGlobalLock) { + if (isMonitoringTransition()) { + Slog.w(TAG, "Previous animation hasn't finish, status: " + mAnimationHandler); + // Don't start any animation for it. + return null; + } WindowManagerInternal windowManagerInternal = LocalServices.getService(WindowManagerInternal.class); IBinder focusedWindowToken = windowManagerInternal.getFocusedWindowToken(); @@ -262,14 +273,23 @@ class BackNavigationController { if (!isOccluded || prevActivity.canShowWhenLocked()) { // We have another Activity in the same currentTask to go to final WindowContainer parent = currentActivity.getParent(); - final boolean isCustomize = parent != null + final boolean canCustomize = parent != null && (parent.asTask() != null || (parent.asTaskFragment() != null - && parent.canCustomizeAppTransition())) - && isCustomizeExitAnimation(window); - if (isCustomize) { - infoBuilder.setWindowAnimations( - window.mAttrs.packageName, window.mAttrs.windowAnimations); + && parent.canCustomizeAppTransition())); + if (canCustomize) { + if (isCustomizeExitAnimation(window)) { + infoBuilder.setWindowAnimations( + window.mAttrs.packageName, window.mAttrs.windowAnimations); + } + final ActivityRecord.CustomAppTransition customAppTransition = + currentActivity.getCustomAnimation(false/* open */); + if (customAppTransition != null) { + infoBuilder.setCustomAnimation(currentActivity.packageName, + customAppTransition.mExitAnim, + customAppTransition.mEnterAnim, + customAppTransition.mBackgroundColor); + } } removedWindowContainer = currentActivity; prevTask = prevActivity.getTask(); @@ -364,7 +384,7 @@ class BackNavigationController { } boolean isMonitoringTransition() { - return isWaitBackTransition() || mNavigationMonitor.isMonitoring(); + return mAnimationHandler.mComposed || mNavigationMonitor.isMonitorForRemote(); } private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) { @@ -467,7 +487,7 @@ class BackNavigationController { return false; } - private static class NavigationMonitor { + private class NavigationMonitor { // The window which triggering the back navigation. private WindowState mNavigatingWindow; private RemoteCallback mObserver; @@ -477,15 +497,23 @@ class BackNavigationController { mObserver = observer; } - void stopMonitor() { - mNavigatingWindow = null; + void stopMonitorForRemote() { mObserver = null; } - boolean isMonitoring() { + void stopMonitorTransition() { + mNavigatingWindow = null; + } + + boolean isMonitorForRemote() { return mNavigatingWindow != null && mObserver != null; } + boolean isMonitorAnimationOrTransition() { + return mNavigatingWindow != null + && (mAnimationHandler.mComposed || mAnimationHandler.mWaitTransition); + } + /** * Notify focus window changed during back navigation. This will cancel the gesture for * scenarios like: a system window popup, or when an activity add a new window. @@ -496,7 +524,8 @@ class BackNavigationController { * a short time, but we should not cancel the navigation. */ private void onFocusWindowChanged(WindowState newFocus) { - if (!isMonitoring() || !atSameDisplay(newFocus)) { + if (!atSameDisplay(newFocus) + || !(isMonitorForRemote() || isMonitorAnimationOrTransition())) { return; } // Keep navigating if either new focus == navigating window or null. @@ -504,7 +533,13 @@ class BackNavigationController { && (newFocus.mActivityRecord == null || (newFocus.mActivityRecord == mNavigatingWindow.mActivityRecord))) { EventLogTags.writeWmBackNaviCanceled("focusWindowChanged"); - mObserver.sendResult(null /* result */); + if (isMonitorForRemote()) { + mObserver.sendResult(null /* result */); + } + if (isMonitorAnimationOrTransition()) { + // transition won't happen, cancel internal status + clearBackAnimations(); + } } } @@ -513,7 +548,7 @@ class BackNavigationController { */ private void onTransitionReadyWhileNavigate(ArrayList<WindowContainer> opening, ArrayList<WindowContainer> closing) { - if (!isMonitoring()) { + if (!isMonitorForRemote() && !isMonitorAnimationOrTransition()) { return; } final ArrayList<WindowContainer> all = new ArrayList<>(opening); @@ -521,7 +556,12 @@ class BackNavigationController { for (WindowContainer app : all) { if (app.hasChild(mNavigatingWindow)) { EventLogTags.writeWmBackNaviCanceled("transitionHappens"); - mObserver.sendResult(null /* result */); + if (isMonitorForRemote()) { + mObserver.sendResult(null /* result */); + } + if (isMonitorAnimationOrTransition()) { + clearBackAnimations(); + } break; } } @@ -529,6 +569,9 @@ class BackNavigationController { } private boolean atSameDisplay(WindowState newFocus) { + if (mNavigatingWindow == null) { + return false; + } final int navigatingDisplayId = mNavigatingWindow.getDisplayId(); return newFocus == null || newFocus.getDisplayId() == navigatingDisplayId; } @@ -536,17 +579,15 @@ class BackNavigationController { // For shell transition /** - * Check whether the transition targets was animated by back gesture animation. - * Because the opening target could request to do other stuff at onResume, so it could become - * close target for a transition. So the condition here is - * The closing target should only exist in close list, but the opening target can be either in - * open or close list. - * @return {@code true} if the participants of this transition was animated by back gesture - * animations, and shouldn't join next transition. + * Check whether the transition targets was animated by back gesture animation. + * Because the opening target could request to do other stuff at onResume, so it could become + * close target for a transition. So the condition here is + * The closing target should only exist in close list, but the opening target can be either in + * open or close list. */ - boolean containsBackAnimationTargets(Transition transition) { + void onTransactionReady(Transition transition) { if (!isMonitoringTransition()) { - return false; + return; } final ArraySet<WindowContainer> targets = transition.mParticipants; for (int i = targets.size() - 1; i >= 0; --i) { @@ -566,33 +607,44 @@ class BackNavigationController { && mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps); if (!matchAnimationTargets) { mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps); + } else { + if (mWaitTransitionFinish != null) { + Slog.e(TAG, "Gesture animation is applied on another transition?"); + } + mWaitTransitionFinish = transition; } mTmpOpenApps.clear(); mTmpCloseApps.clear(); - return matchAnimationTargets; } boolean isMonitorTransitionTarget(WindowContainer wc) { - if (!isWaitBackTransition()) { + if (!isWaitBackTransition() || mWaitTransitionFinish == null) { return false; } return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */); } /** - * Cleanup animation, this can either happen when transition ready or finish. - * @param cleanupTransaction The transaction which the caller want to apply the internal - * cleanup together. + * Cleanup animation, this can either happen when legacy transition ready, or when the Shell + * transition finish. */ - void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) { - mAnimationHandler.clearBackAnimateTarget(cleanupTransaction); + void clearBackAnimations() { + mAnimationHandler.clearBackAnimateTarget(); + mNavigationMonitor.stopMonitorTransition(); + mWaitTransitionFinish = null; } - /** + /** + * Called when a transition finished. * Handle the pending animation when the running transition finished. * @param targets The final animation targets derived in transition. - */ - boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) { + * @param finishedTransition The finished transition target. + */ + boolean onTransitionFinish(ArrayList<Transition.ChangeInfo> targets, + @NonNull Transition finishedTransition) { + if (finishedTransition == mWaitTransitionFinish) { + clearBackAnimations(); + } if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) { return false; } @@ -642,14 +694,15 @@ class BackNavigationController { /** * Create and handling animations status for an open/close animation targets. */ - private static class AnimationHandler { + static class AnimationHandler { + private final boolean mShowWindowlessSurface; private final WindowManagerService mWindowManagerService; private BackWindowAnimationAdaptor mCloseAdaptor; private BackWindowAnimationAdaptor mOpenAdaptor; private boolean mComposed; private boolean mWaitTransition; private int mSwitchType = UNKNOWN; - private SurfaceControl.Transaction mFinishedTransaction; + // This will be set before transition happen, to know whether the real opening target // exactly match animating target. When target match, reparent the starting surface to // the opening target like starting window do. @@ -658,22 +711,42 @@ class BackNavigationController { // request one during animating. private int mRequestedStartingSurfaceTaskId; private SurfaceControl mStartingSurface; + private ActivityRecord mOpenActivity; AnimationHandler(WindowManagerService wms) { mWindowManagerService = wms; + final Context context = wms.mContext; + mShowWindowlessSurface = context.getResources().getBoolean( + com.android.internal.R.bool.config_predictShowStartingSurface); } private static final int UNKNOWN = 0; private static final int TASK_SWITCH = 1; private static final int ACTIVITY_SWITCH = 2; - private void initiate(WindowContainer close, WindowContainer open) { + private static boolean isActivitySwitch(WindowContainer close, WindowContainer open) { + if (close.asActivityRecord() == null || open.asActivityRecord() == null + || (close.asActivityRecord().getTask() + != open.asActivityRecord().getTask())) { + return false; + } + return true; + } + + private static boolean isTaskSwitch(WindowContainer close, WindowContainer open) { + if (close.asTask() == null || open.asTask() == null + || (close.asTask() == open.asTask())) { + return false; + } + return true; + } + + private void initiate(WindowContainer close, WindowContainer open, + ActivityRecord openActivity) { WindowContainer closeTarget; - if (close.asActivityRecord() != null && open.asActivityRecord() != null - && (close.asActivityRecord().getTask() == open.asActivityRecord().getTask())) { + if (isActivitySwitch(close, open)) { mSwitchType = ACTIVITY_SWITCH; closeTarget = close.asActivityRecord(); - } else if (close.asTask() != null && open.asTask() != null - && close.asTask() != open.asTask()) { + } else if (isTaskSwitch(close, open)) { mSwitchType = TASK_SWITCH; closeTarget = close.asTask().getTopNonFinishingActivity(); } else { @@ -683,21 +756,26 @@ class BackNavigationController { mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */); mOpenAdaptor = createAdaptor(open, true /* isOpen */); - + mOpenActivity = openActivity; if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) { Slog.w(TAG, "composeNewAnimations fail, skip"); - clearBackAnimateTarget(null /* cleanupTransaction */); + clearBackAnimateTarget(); } } - boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { - clearBackAnimateTarget(null /* cleanupTransaction */); - if (close == null || open == null) { + boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open, + ActivityRecord openActivity) { + if (mComposed || mWaitTransition) { + Slog.e(TAG, "Previous animation is running " + this); + return false; + } + clearBackAnimateTarget(); + if (close == null || open == null || openActivity == null) { Slog.e(TAG, "reset animation with null target close: " + close + " open: " + open); return false; } - initiate(close, open); + initiate(close, open, openActivity); if (mSwitchType == UNKNOWN) { return false; } @@ -748,37 +826,23 @@ class BackNavigationController { } boolean isTarget(WindowContainer wc, boolean open) { - if (open) { - return wc == mOpenAdaptor.mTarget || mOpenAdaptor.mTarget.hasChild(wc); + if (!mComposed) { + return false; } - + final WindowContainer target = open ? mOpenAdaptor.mTarget : mCloseAdaptor.mTarget; if (mSwitchType == TASK_SWITCH) { - return wc == mCloseAdaptor.mTarget - || (wc.asTask() != null && wc.hasChild(mCloseAdaptor.mTarget)); + return wc == target + || (wc.asTask() != null && wc.hasChild(target)); } else if (mSwitchType == ACTIVITY_SWITCH) { - return wc == mCloseAdaptor.mTarget; + return wc == target || (wc.asTaskFragment() != null && wc.hasChild(target)); } return false; } - boolean setFinishTransaction(SurfaceControl.Transaction finishTransaction) { - if (!mComposed) { - return false; - } - mFinishedTransaction = finishTransaction; - return true; - } - - void finishPresentAnimations(SurfaceControl.Transaction t) { + void finishPresentAnimations() { if (!mComposed) { return; } - final SurfaceControl.Transaction pt = t != null ? t - : mOpenAdaptor.mTarget.getPendingTransaction(); - if (mFinishedTransaction != null) { - pt.merge(mFinishedTransaction); - mFinishedTransaction = null; - } cleanUpWindowlessSurface(); if (mCloseAdaptor != null) { @@ -789,6 +853,9 @@ class BackNavigationController { mOpenAdaptor.mTarget.cancelAnimation(); mOpenAdaptor = null; } + if (mOpenActivity != null && mOpenActivity.mLaunchTaskBehind) { + restoreLaunchBehind(mOpenActivity); + } } private void cleanUpWindowlessSurface() { @@ -815,22 +882,14 @@ class BackNavigationController { } } - void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) { - finishPresentAnimations(cleanupTransaction); + void clearBackAnimateTarget() { + finishPresentAnimations(); mComposed = false; mWaitTransition = false; mOpenTransitionTargetMatch = false; mRequestedStartingSurfaceTaskId = 0; mSwitchType = UNKNOWN; - if (mFinishedTransaction != null) { - Slog.w(TAG, "Clear back animation, found un-processed finished transaction"); - if (cleanupTransaction != null) { - cleanupTransaction.merge(mFinishedTransaction); - } else { - mFinishedTransaction.apply(); - } - mFinishedTransaction = null; - } + mOpenActivity = null; } // The close target must in close list @@ -846,9 +905,9 @@ class BackNavigationController { public String toString() { return "AnimationTargets{" + " openTarget= " - + mOpenAdaptor.mTarget + + (mOpenAdaptor != null ? mOpenAdaptor.mTarget : "null") + " closeTarget= " - + mCloseAdaptor.mTarget + + (mCloseAdaptor != null ? mCloseAdaptor.mTarget : "null") + " mSwitchType= " + mSwitchType + " mComposed= " @@ -974,21 +1033,20 @@ class BackNavigationController { case BackNavigationInfo.TYPE_CROSS_ACTIVITY: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentActivity, previousActivity) - .setOpeningSnapshot(getActivitySnapshot(previousActivity)); + .setIsLaunchBehind(false); case BackNavigationInfo.TYPE_CROSS_TASK: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentTask, previousTask) - .setOpeningSnapshot(getTaskSnapshot(previousTask)); + .setIsLaunchBehind(false); } return null; } - private class ScheduleAnimationBuilder { + class ScheduleAnimationBuilder { final int mType; final BackAnimationAdapter mBackAnimationAdapter; WindowContainer mCloseTarget; WindowContainer mOpenTarget; - TaskSnapshot mOpenSnapshot; boolean mIsLaunchBehind; ScheduleAnimationBuilder(int type, BackAnimationAdapter backAnimationAdapter) { @@ -1002,11 +1060,6 @@ class BackNavigationController { return this; } - ScheduleAnimationBuilder setOpeningSnapshot(TaskSnapshot snapshot) { - mOpenSnapshot = snapshot; - return this; - } - ScheduleAnimationBuilder setIsLaunchBehind(boolean launchBehind) { mIsLaunchBehind = launchBehind; return this; @@ -1017,37 +1070,41 @@ class BackNavigationController { || wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget); } + /** + * Apply preview strategy on the opening target + * @param open The opening target. + * @param visibleOpenActivity The visible activity in opening target. + * @return If the preview strategy is launch behind, returns the Activity that has + * launchBehind set, or null otherwise. + */ + private void applyPreviewStrategy(WindowContainer open, + ActivityRecord visibleOpenActivity) { + if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) { + createStartingSurface(getSnapshot(open)); + return; + } + setLaunchBehind(visibleOpenActivity); + } + Runnable build() { if (mOpenTarget == null || mCloseTarget == null) { return null; } - final boolean shouldLaunchBehind = mIsLaunchBehind || !isSupportWindowlessSurface(); - final ActivityRecord launchBehindActivity = !shouldLaunchBehind ? null - : mOpenTarget.asTask() != null + final ActivityRecord openActivity = mOpenTarget.asTask() != null ? mOpenTarget.asTask().getTopNonFinishingActivity() : mOpenTarget.asActivityRecord() != null ? mOpenTarget.asActivityRecord() : null; - if (shouldLaunchBehind && launchBehindActivity == null) { + if (openActivity == null) { Slog.e(TAG, "No opening activity"); return null; } - if (!composeAnimations(mCloseTarget, mOpenTarget)) { + if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) { return null; } - if (launchBehindActivity != null) { - setLaunchBehind(launchBehindActivity); - } else { - createStartingSurface(mOpenSnapshot); - } + applyPreviewStrategy(mOpenTarget, openActivity); - final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback( - launchBehindActivity != null ? triggerBack -> { - if (!triggerBack) { - restoreLaunchBehind(launchBehindActivity); - } - } : null, - mCloseTarget); + final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(); final RemoteAnimationTarget[] targets = getAnimationTargets(); return () -> { @@ -1060,31 +1117,17 @@ class BackNavigationController { }; } - private IBackAnimationFinishedCallback makeAnimationFinishedCallback( - Consumer<Boolean> b, WindowContainer closeTarget) { + private IBackAnimationFinishedCallback makeAnimationFinishedCallback() { return new IBackAnimationFinishedCallback.Stub() { @Override public void onAnimationFinished(boolean triggerBack) { - final SurfaceControl.Transaction finishedTransaction = - new SurfaceControl.Transaction(); synchronized (mWindowManagerService.mGlobalLock) { - if (b != null) { - b.accept(triggerBack); - } - if (triggerBack) { - final SurfaceControl surfaceControl = - closeTarget.getSurfaceControl(); - if (surfaceControl != null && surfaceControl.isValid()) { - // Hide the close target surface when transition start. - finishedTransaction.hide(surfaceControl); - } - } - if (!setFinishTransaction(finishedTransaction)) { - finishedTransaction.apply(); + if (!mComposed) { + // animation was canceled + return; } if (!triggerBack) { - clearBackAnimateTarget( - null /* cleanupTransaction */); + clearBackAnimateTarget(); } else { mWaitTransition = true; } @@ -1144,6 +1187,14 @@ class BackNavigationController { } void startAnimation() { + if (!mBackAnimationInProgress) { + // gesture is already finished, do not start animation + if (mPendingAnimation != null) { + clearBackAnimations(); + mPendingAnimation = null; + } + return; + } if (mPendingAnimation != null) { mPendingAnimation.run(); mPendingAnimation = null; @@ -1156,31 +1207,28 @@ class BackNavigationController { ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, " + "triggerBack=%b", backType, triggerBack); - mNavigationMonitor.stopMonitor(); + mNavigationMonitor.stopMonitorForRemote(); mBackAnimationInProgress = false; mShowWallpaper = false; mPendingAnimationBuilder = null; } - private static TaskSnapshot getActivitySnapshot(@NonNull ActivityRecord r) { + static TaskSnapshot getSnapshot(@NonNull WindowContainer w) { if (!isScreenshotEnabled()) { return null; } - // Check if we have a screenshot of the previous activity, indexed by its - // component name. - // TODO return TaskSnapshot when feature complete. -// final HardwareBuffer hw = r.getTask().getSnapshotForActivityRecord(r); - return null; - } + if (w.asTask() != null) { + final Task task = w.asTask(); + return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( + task.mTaskId, task.mUserId, false /* restoreFromDisk */, + false /* isLowResolution */); + } - private static TaskSnapshot getTaskSnapshot(Task task) { - if (!isScreenshotEnabled()) { + if (w.asActivityRecord() != null) { + // TODO (b/259497289) return TaskSnapshot when feature complete. return null; } - // Don't read from disk!! - return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( - task.mTaskId, task.mUserId, false /* restoreFromDisk */, - false /* isLowResolution */); + return null; } void setWindowManager(WindowManagerService wm) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 37ee2e2a1187..a44f25ca8051 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1567,7 +1567,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (configChanged) { mWaitingForConfig = true; if (mTransitionController.isShellTransitionsEnabled()) { - requestChangeTransitionIfNeeded(changes, null /* displayChange */); + final TransitionRequestInfo.DisplayChange change = + mTransitionController.isCollecting() + ? null : new TransitionRequestInfo.DisplayChange(mDisplayId); + if (change != null) { + change.setStartAbsBounds(currentDisplayConfig.windowConfiguration.getBounds()); + change.setEndAbsBounds(mTmpConfiguration.windowConfiguration.getBounds()); + } + requestChangeTransitionIfNeeded(changes, change); } else if (mLastHasContent) { mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this); } @@ -3293,7 +3300,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Unlink death from remote to clear the reference from binder -> mRemoteInsetsDeath // -> this DisplayContent. setRemoteInsetsController(null); - mWmService.mAnimator.removeDisplayLocked(mDisplayId); mOverlayLayer.release(); mA11yOverlayLayer.release(); mWindowingLayer.release(); @@ -5305,8 +5311,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // {@link DisplayContent} ready for use. mDisplayReady = true; - mWmService.mAnimator.addDisplayLocked(mDisplayId); - if (mWmService.mDisplayManagerInternal != null) { mWmService.mDisplayManagerInternal .setDisplayInfoOverrideFromWindowManager(mDisplayId, getDisplayInfo()); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 72263ffc7de2..6af1c7c9d656 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -87,8 +87,6 @@ import java.util.Set; */ public class DisplayRotation { private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM; - // Delay to avoid race between fold update and orientation update. - private static final int ORIENTATION_UPDATE_DELAY_MS = 800; // Delay in milliseconds when updating config due to folding events. This prevents // config changes and unexpected jumps while folding the device to closed state. @@ -1789,15 +1787,15 @@ public class DisplayRotation { mDeviceState = newState; // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will // return true, so rotation is unlocked. + mService.updateRotation(false /* alwaysSendConfiguration */, + false /* forceRelayout */); } else { mInHalfFoldTransition = true; mDeviceState = newState; + // Tell the device to update its orientation. + mService.updateRotation(false /* alwaysSendConfiguration */, + false /* forceRelayout */); } - UiThread.getHandler().postDelayed( - () -> { - mService.updateRotation(false /* alwaysSendConfiguration */, - false /* forceRelayout */); - }, ORIENTATION_UPDATE_DELAY_MS); // Alert the activity of possible new bounds. UiThread.getHandler().removeCallbacks(mActivityBoundsUpdateCallback); UiThread.getHandler().postDelayed(mActivityBoundsUpdateCallback, diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index c3c727a1d879..052c09a0e0eb 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -326,7 +326,7 @@ class EmbeddedWindowController { @Override public boolean shouldControlIme() { - return false; + return mHostWindowState != null; } @Override @@ -336,6 +336,9 @@ class EmbeddedWindowController { @Override public InsetsControlTarget getImeControlTarget() { + if (mHostWindowState != null) { + return mHostWindowState.getImeControlTarget(); + } return mWmService.getDefaultDisplayContentLocked().mRemoteInsetsControlTarget; } @@ -346,7 +349,7 @@ class EmbeddedWindowController { @Override public ActivityRecord getActivityRecord() { - return null; + return mHostActivityRecord; } @Override diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 868a15d3c977..a8c9cd30b656 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -334,7 +334,11 @@ class InsetsPolicy { // remove caption insets from floating windows. // TODO(b/254128050): Remove this workaround after we find a way to update window frames // and caption insets frames simultaneously. - state.removeSource(InsetsState.ITYPE_CAPTION_BAR); + for (int i = state.sourceSize() - 1; i >= 0; i--) { + if (state.sourceAt(i).getType() == Type.captionBar()) { + state.removeSourceAt(i); + } + } } final SparseArray<WindowContainerInsetsSourceProvider> providers = diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index dda0d6c3c3f2..b38666522754 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -976,9 +976,10 @@ class RecentTasks { if (!task.mUserSetupComplete) { // Don't include task launched while user is not done setting-up. - if (DEBUG_RECENTS) { - Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + task); - } + + // NOTE: not guarding with DEBUG_RECENTS as it's not frequent enough to spam logcat, + // but is useful when running CTS. + Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + task); continue; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 2f5634362e68..07daa4b22ac9 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2349,12 +2349,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } // Prepare transition before resume top activity, so it can be collected. - if (!displayShouldSleep && display.isDefaultDisplay - && !display.getDisplayPolicy().isAwake() - && display.mTransitionController.isShellTransitionsEnabled() + if (!displayShouldSleep && display.mTransitionController.isShellTransitionsEnabled() && !display.mTransitionController.isCollecting()) { - display.mTransitionController.requestTransitionIfNeeded(TRANSIT_WAKE, - 0 /* flags */, null /* trigger */, display); + int transit = TRANSIT_NONE; + if (!display.getDisplayPolicy().isAwake()) { + // Note that currently this only happens on default display because non-default + // display is always awake. + transit = TRANSIT_WAKE; + } else if (display.isKeyguardOccluded()) { + // The display was awake so this is resuming activity for occluding keyguard. + transit = WindowManager.TRANSIT_KEYGUARD_OCCLUDE; + } + if (transit != TRANSIT_NONE) { + display.mTransitionController.requestStartTransition( + display.mTransitionController.createTransition(transit), + null /* startTask */, null /* remoteTransition */, + null /* displayChange */); + } } // Set the sleeping state of the root tasks on the display. display.forAllRootTasks(rootTask -> { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 5a4615ad9578..b7e2265e3a16 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5636,8 +5636,6 @@ class Task extends TaskFragment { mWmService.mSyncEngine.queueSyncSet( () -> mTransitionController.moveToCollecting(transition), () -> { - mTransitionController.requestStartTransition(transition, tr, - null /* remoteTransition */, null /* displayChange */); // Need to check again since this happens later and the system might // be in a different state. if (!canMoveTaskToBack(tr)) { @@ -5646,6 +5644,8 @@ class Task extends TaskFragment { transition.abort(); return; } + mTransitionController.requestStartTransition(transition, tr, + null /* remoteTransition */, null /* displayChange */); moveTaskToBackInner(tr); }); } else { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 2cfd2af89c80..c6ba60026cdf 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -66,6 +66,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.IApplicationThread; import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; @@ -83,7 +84,6 @@ import android.util.SparseArray; import android.view.Display; import android.view.SurfaceControl; import android.view.WindowManager; -import android.window.RemoteTransition; import android.window.ScreenCapture; import android.window.TransitionInfo; @@ -160,7 +160,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { private final TransitionController mController; private final BLASTSyncEngine mSyncEngine; private final Token mToken; - private RemoteTransition mRemoteTransition = null; + private IApplicationThread mRemoteAnimApp; /** Only use for clean-up after binder death! */ private SurfaceControl.Transaction mStartTransaction = null; @@ -783,7 +783,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { * a chance we won't thus legacy-entry (via pause+userLeaving) will return false. */ private boolean checkEnterPipOnFinish(@NonNull ActivityRecord ar) { - if (!mCanPipOnFinish || !ar.isVisible() || ar.getTask() == null) return false; + if (!mCanPipOnFinish || !ar.isVisible() || ar.getTask() == null || !ar.isState(RESUMED)) { + return false; + } if (ar.pictureInPictureArgs != null && ar.pictureInPictureArgs.isAutoEnterEnabled()) { if (didCommitTransientLaunch()) { @@ -796,18 +798,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } // Legacy pip-entry (not via isAutoEnterEnabled). - boolean canPip = ar.getDeferHidingClient(); - if (!canPip && didCommitTransientLaunch()) { + if (didCommitTransientLaunch() && ar.supportsPictureInPicture()) { // force enable pip-on-task-switch now that we've committed to actually launching to the // transient activity, and then recalculate whether we can attempt pip. ar.supportsEnterPipOnTaskSwitch = true; - canPip = ar.checkEnterPictureInPictureState( - "finishTransition", true /* beforeStopping */) - && ar.isState(RESUMED); } - if (!canPip) return false; + try { - // Legacy PIP-enter requires pause event with user-leaving. + // If not going auto-pip, the activity should be paused with user-leaving. mController.mAtm.mTaskSupervisor.mUserLeaving = true; ar.getTaskFragment().startPausing(false /* uiSleeping */, null /* resuming */, "finishTransition"); @@ -851,6 +849,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { boolean hasParticipatedDisplay = false; boolean hasVisibleTransientLaunch = false; + boolean enterAutoPip = false; // Commit all going-invisible containers for (int i = 0; i < mParticipants.size(); ++i) { final WindowContainer<?> participant = mParticipants.valueAt(i); @@ -886,6 +885,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } ar.commitVisibility(false /* visible */, false /* performLayout */, true /* fromTransition */); + } else { + enterAutoPip = true; } } if (mChanges.get(ar).mVisible != visibleAtTransitionEnd) { @@ -940,8 +941,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } if (hasVisibleTransientLaunch) { - // Notify the change about the transient-below task that becomes invisible. - mController.mAtm.getTaskChangeNotificationController().notifyTaskStackChanged(); + // Notify the change about the transient-below task if entering auto-pip. + if (enterAutoPip) { + mController.mAtm.getTaskChangeNotificationController().notifyTaskStackChanged(); + } // Prevent spurious background app switches. mController.mAtm.stopAppSwitches(); // The end of transient launch may not reorder task, so make sure to compute the latest @@ -1031,7 +1034,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTmpTransaction.apply(); // Handle back animation if it's already started. - mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets); + mController.mAtm.mBackNavigationController.onTransitionFinish(mTargets, this); mController.mFinishingTransition = null; } @@ -1075,12 +1078,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return mForcePlaying; } - void setRemoteTransition(RemoteTransition remoteTransition) { - mRemoteTransition = remoteTransition; + void setRemoteAnimationApp(IApplicationThread app) { + mRemoteAnimApp = app; } - RemoteTransition getRemoteTransition() { - return mRemoteTransition; + /** Returns the app which will run the transition animation. */ + IApplicationThread getRemoteAnimationApp() { + return mRemoteAnimApp; } void setNoAnimation(WindowContainer wc) { @@ -1135,8 +1139,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED; } // Check whether the participants were animated from back navigation. - final boolean markBackAnimated = mController.mAtm.mBackNavigationController - .containsBackAnimationTargets(this); + mController.mAtm.mBackNavigationController.onTransactionReady(this); // Resolve the animating targets from the participants. mTargets = calculateTargets(mParticipants, mChanges); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction); @@ -1149,9 +1152,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTargetDisplays.add(dc); } - if (markBackAnimated) { - mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction); - } if (mOverrideOptions != null) { info.setAnimationOptions(mOverrideOptions); if (mOverrideOptions.getType() == ANIM_OPEN_CROSS_PROFILE_APPS) { @@ -2363,6 +2363,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (isTranslucent(wc)) { flags |= FLAG_TRANSLUCENT; } + if (wc.mWmService.mAtmService.mBackNavigationController.isMonitorTransitionTarget(wc)) { + flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; + } final Task task = wc.asTask(); if (task != null) { final ActivityRecord topActivity = task.getTopNonFinishingActivity(); @@ -2371,19 +2374,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { && topActivity.mStartingData.hasImeSurface()) { flags |= FLAG_WILL_IME_SHOWN; } - if (topActivity.mAtmService.mBackNavigationController - .isMonitorTransitionTarget(topActivity)) { - flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; - } - if (topActivity != null && topActivity.mLaunchTaskBehind) { + if (topActivity.mLaunchTaskBehind) { Slog.e(TAG, "Unexpected launch-task-behind operation in shell transition"); flags |= FLAG_TASK_LAUNCHING_BEHIND; } - } else { - if (task.mAtmService.mBackNavigationController - .isMonitorTransitionTarget(task)) { - flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; - } } if (task.voiceSession != null) { flags |= FLAG_IS_VOICE_INTERACTION; @@ -2397,10 +2391,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { flags |= FLAG_IS_VOICE_INTERACTION; } flags |= record.mTransitionChangeFlags; - if (record.mAtmService.mBackNavigationController - .isMonitorTransitionTarget(record)) { - flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; - } } final TaskFragment taskFragment = wc.asTaskFragment(); if (taskFragment != null && task == null) { diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index f314b21a0d72..bcb8c46de5ed 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -30,6 +30,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IApplicationThread; import android.app.WindowConfiguration; +import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; @@ -465,6 +466,28 @@ class TransitionController { return type == TRANSIT_OPEN || type == TRANSIT_CLOSE; } + /** Whether the display change should run with blast sync. */ + private static boolean shouldSync(@NonNull TransitionRequestInfo.DisplayChange displayChange) { + if ((displayChange.getStartRotation() + displayChange.getEndRotation()) % 2 == 0) { + // 180 degrees rotation change may not change screen size. So the clients may draw + // some frames before and after the display projection transaction is applied by the + // remote player. That may cause some buffers to show in different rotation. So use + // sync method to pause clients drawing until the projection transaction is applied. + return true; + } + final Rect startBounds = displayChange.getStartAbsBounds(); + final Rect endBounds = displayChange.getEndAbsBounds(); + if (startBounds == null || endBounds == null) return false; + final int startWidth = startBounds.width(); + final int startHeight = startBounds.height(); + final int endWidth = endBounds.width(); + final int endHeight = endBounds.height(); + // This is changing screen resolution. Because the screen decor layers are excluded from + // screenshot, their draw transactions need to run with the start transaction. + return (endWidth > startWidth) == (endHeight > startHeight) + && (endWidth != startWidth || endHeight != startHeight); + } + /** * If a transition isn't requested yet, creates one and asks the TransitionPlayer (Shell) to * start it. Collection can start immediately. @@ -494,12 +517,7 @@ class TransitionController { } else { newTransition = requestStartTransition(createTransition(type, flags), trigger != null ? trigger.asTask() : null, remoteTransition, displayChange); - if (newTransition != null && displayChange != null && (displayChange.getStartRotation() - + displayChange.getEndRotation()) % 2 == 0) { - // 180 degrees rotation change may not change screen size. So the clients may draw - // some frames before and after the display projection transaction is applied by the - // remote player. That may cause some buffers to show in different rotation. So use - // sync method to pause clients drawing until the projection transaction is applied. + if (newTransition != null && displayChange != null && shouldSync(displayChange)) { mAtm.mWindowManager.mSyncEngine.setSyncMethod(newTransition.getSyncId(), BLASTSyncEngine.METHOD_BLAST); } @@ -549,7 +567,9 @@ class TransitionController { transition.mLogger.mRequestTimeNs = SystemClock.elapsedRealtimeNanos(); transition.mLogger.mRequest = request; mTransitionPlayer.requestStartTransition(transition.getToken(), request); - transition.setRemoteTransition(remoteTransition); + if (remoteTransition != null) { + transition.setRemoteAnimationApp(remoteTransition.getAppThread()); + } } catch (RemoteException e) { Slog.e(TAG, "Error requesting transition", e); transition.start(); @@ -761,9 +781,8 @@ class TransitionController { mRemotePlayer.clear(); return; } - final RemoteTransition remote = transition.getRemoteTransition(); - if (remote == null) return; - final IApplicationThread appThread = remote.getAppThread(); + final IApplicationThread appThread = transition.getRemoteAnimationApp(); + if (appThread == null || appThread == mTransitionPlayerProc.getThread()) return; final WindowProcessController delegate = mAtm.getProcessController(appThread); if (delegate == null) return; mRemotePlayer.update(delegate, isPlaying, true /* predict */); diff --git a/services/core/java/com/android/server/wm/VrController.java b/services/core/java/com/android/server/wm/VrController.java index 9e159aba4d77..241a8ae88ae7 100644 --- a/services/core/java/com/android/server/wm/VrController.java +++ b/services/core/java/com/android/server/wm/VrController.java @@ -126,6 +126,9 @@ final class VrController { } }; + /** If it is null after system ready, then VR mode is not supported. */ + VrManagerInternal mVrService; + /** * Create new VrController instance. * @@ -141,6 +144,7 @@ final class VrController { public void onSystemReady() { VrManagerInternal vrManagerInternal = LocalServices.getService(VrManagerInternal.class); if (vrManagerInternal != null) { + mVrService = vrManagerInternal; vrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener); } } @@ -181,7 +185,7 @@ final class VrController { public boolean onVrModeChanged(ActivityRecord record) { // This message means that the top focused activity enabled VR mode (or an activity // that previously set this has become focused). - VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); + final VrManagerInternal vrService = mVrService; if (vrService == null) { // VR mode isn't supported on this device. return false; diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 10bedd4b921f..adc0595f305b 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -30,7 +30,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.content.Context; import android.os.Trace; import android.util.Slog; -import android.util.SparseArray; import android.util.TimeUtils; import android.view.Choreographer; import android.view.SurfaceControl; @@ -66,7 +65,6 @@ public class WindowAnimator { int mBulkUpdateParams = 0; Object mLastWindowFreezeSource; - SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2); private boolean mInitialized = false; private Choreographer mChoreographer; @@ -98,8 +96,7 @@ public class WindowAnimator { mAnimationFrameCallback = frameTimeNs -> { synchronized (mService.mGlobalLock) { mAnimationFrameCallbackScheduled = false; - final long vsyncId = mChoreographer.getVsyncId(); - animate(frameTimeNs, vsyncId); + animate(frameTimeNs); if (mNotifyWhenNoAnimation && !mLastRootAnimating) { mService.mGlobalLock.notifyAll(); } @@ -107,21 +104,11 @@ public class WindowAnimator { }; } - void addDisplayLocked(final int displayId) { - // Create the DisplayContentsAnimator object by retrieving it if the associated - // {@link DisplayContent} exists. - getDisplayContentsAnimatorLocked(displayId); - } - - void removeDisplayLocked(final int displayId) { - mDisplayContentsAnimators.delete(displayId); - } - void ready() { mInitialized = true; } - private void animate(long frameTimeNs, long vsyncId) { + private void animate(long frameTimeNs) { if (!mInitialized) { return; } @@ -145,10 +132,9 @@ public class WindowAnimator { final AccessibilityController accessibilityController = mService.mAccessibilityController; - final int numDisplays = mDisplayContentsAnimators.size(); + final int numDisplays = root.getChildCount(); for (int i = 0; i < numDisplays; i++) { - final int displayId = mDisplayContentsAnimators.keyAt(i); - final DisplayContent dc = root.getDisplayContent(displayId); + final DisplayContent dc = root.getChildAt(i); // Update animations of all applications, including those associated with // exiting/removed apps. dc.updateWindowsForAnimator(); @@ -156,12 +142,11 @@ public class WindowAnimator { } for (int i = 0; i < numDisplays; i++) { - final int displayId = mDisplayContentsAnimators.keyAt(i); - final DisplayContent dc = root.getDisplayContent(displayId); + final DisplayContent dc = root.getChildAt(i); dc.checkAppWindowsReadyToShow(); if (accessibilityController.hasCallbacks()) { - accessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId, + accessibilityController.drawMagnifiedRegionBorderIfNeeded(dc.mDisplayId, mTransaction); } } @@ -237,12 +222,9 @@ public class WindowAnimator { public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) { final String subPrefix = " " + prefix; - for (int i = 0; i < mDisplayContentsAnimators.size(); i++) { - pw.print(prefix); pw.print("DisplayContentsAnimator #"); - pw.print(mDisplayContentsAnimators.keyAt(i)); - pw.println(":"); - final DisplayContent dc = - mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i)); + for (int i = 0; i < mService.mRoot.getChildCount(); i++) { + final DisplayContent dc = mService.mRoot.getChildAt(i); + pw.print(prefix); pw.print(dc); pw.println(":"); dc.dumpWindowAnimators(pw, subPrefix); pw.println(); } @@ -260,23 +242,6 @@ public class WindowAnimator { } } - private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) { - if (displayId < 0) { - return null; - } - - DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId); - - // It is possible that this underlying {@link DisplayContent} has been removed. In this - // case, we do not want to create an animator associated with it as {link #animate} will - // fail. - if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) { - displayAnimator = new DisplayContentsAnimator(); - mDisplayContentsAnimators.put(displayId, displayAnimator); - } - return displayAnimator; - } - void scheduleAnimation() { if (!mAnimationFrameCallbackScheduled) { mAnimationFrameCallbackScheduled = true; @@ -291,9 +256,6 @@ public class WindowAnimator { } } - private class DisplayContentsAnimator { - } - boolean isAnimationScheduled() { return mAnimationFrameCallbackScheduled; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c599da84e8d9..a7a90604f228 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -88,7 +88,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED; import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.fixScale; import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW; @@ -7088,6 +7087,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) { + mContext.enforceCallingOrSelfPermission(REGISTER_WINDOW_MANAGER_LISTENERS, + "requestAppKeyboardShortcuts"); + try { WindowState focusedWindow = getFocusedWindow(); if (focusedWindow != null && focusedWindow.mClient != null) { @@ -8534,13 +8536,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - // focus-transfer can re-order windows and thus potentially causes visible changes: - final Transition transition = mAtmService.getTransitionController() - .requestTransitionIfNeeded(TRANSIT_TO_FRONT, task); mAtmService.setFocusedTask(task.mTaskId, touchedActivity); - if (transition != null) { - transition.setReady(task, true /* ready */); - } } /** diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 806a32af4958..32d54d774b40 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -684,12 +684,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } } - final int prevWindowingMode = container.getRequestedOverrideWindowingMode(); - if (windowingMode > -1 && prevWindowingMode != windowingMode) { + if (windowingMode > -1) { if (mService.isInLockTaskMode() && WindowConfiguration.inMultiWindowMode(windowingMode)) { - throw new UnsupportedOperationException("Not supported to set multi-window" - + " windowing mode during locked task mode."); + Slog.w(TAG, "Dropping unsupported request to set multi-window windowing mode" + + " during locked task mode."); + return effects; } if (windowingMode == WindowConfiguration.WINDOWING_MODE_PINNED) { @@ -699,8 +699,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return effects; } + final int prevMode = container.getRequestedOverrideWindowingMode(); container.setWindowingMode(windowingMode); - if (prevWindowingMode != container.getWindowingMode()) { + if (prevMode != container.getWindowingMode()) { // The activity in the container may become focusable or non-focusable due to // windowing modes changes (such as entering or leaving pinned windowing mode), // so also apply the lifecycle effects to this transaction. diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d1bd06f7fa99..232b817b8314 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2343,6 +2343,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // to be removed before the parent (so that the sync-engine tracking works). Since // WindowStateAnimator is a "virtual" child, we have to do it manually here. mWinAnimator.destroySurfaceLocked(getSyncTransaction()); + if (!mDrawHandlers.isEmpty()) { + mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); + } super.removeImmediately(); final DisplayContent dc = getDisplayContent(); diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index a5b1943c6b42..71acbb439c88 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -137,7 +137,6 @@ static struct { jmethodID notifyDropWindow; jmethodID getParentSurfaceForPointers; jmethodID isPerDisplayTouchModeEnabled; - jmethodID isStylusPointerIconEnabled; } gServiceClassInfo; static struct { @@ -309,6 +308,7 @@ public: std::optional<std::string> getBluetoothAddress(int32_t deviceId); void setStylusButtonMotionEventsEnabled(bool enabled); FloatPoint getMouseCursorPosition(); + void setStylusPointerIconEnabled(bool enabled); /* --- InputReaderPolicyInterface implementation --- */ @@ -430,6 +430,9 @@ private: // True to enable a zone on the right-hand side of touchpads where clicks will be turned // into context (a.k.a. "right") clicks. bool touchpadRightClickZoneEnabled{false}; + + // True if a pointer icon should be shown for stylus pointers. + bool stylusPointerIconEnabled{false}; } mLocked GUARDED_BY(mLock); std::atomic<bool> mInteractive; @@ -662,12 +665,6 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon outConfig->pointerGestureTapSlop = hoverTapSlop; } - jboolean stylusPointerIconEnabled = - env->CallBooleanMethod(mServiceObj, gServiceClassInfo.isStylusPointerIconEnabled); - if (!checkAndClearExceptionFromCallback(env, "isStylusPointerIconEnabled")) { - outConfig->stylusPointerIconEnabled = stylusPointerIconEnabled; - } - { // acquire lock std::scoped_lock _l(mLock); @@ -692,6 +689,8 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon outConfig->disabledDevices = mLocked.disabledInputDevices; outConfig->stylusButtonMotionEventsEnabled = mLocked.stylusButtonMotionEventsEnabled; + + outConfig->stylusPointerIconEnabled = mLocked.stylusPointerIconEnabled; } // release lock } @@ -1664,6 +1663,21 @@ FloatPoint NativeInputManager::getMouseCursorPosition() { return pc->getPosition(); } +void NativeInputManager::setStylusPointerIconEnabled(bool enabled) { + { // acquire lock + std::scoped_lock _l(mLock); + + if (mLocked.stylusPointerIconEnabled == enabled) { + return; + } + + mLocked.stylusPointerIconEnabled = enabled; + } // release lock + + mInputManager->getReader().requestRefreshConfiguration( + InputReaderConfiguration::CHANGE_DISPLAY_INFO); +} + // ---------------------------------------------------------------------------- static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) { @@ -2322,6 +2336,14 @@ static void nativeReloadDeviceAliases(JNIEnv* env, jobject nativeImplObj) { InputReaderConfiguration::CHANGE_DEVICE_ALIAS); } +static void nativeSysfsNodeChanged(JNIEnv* env, jobject nativeImplObj, jstring path) { + ScopedUtfChars sysfsNodePathChars(env, path); + const std::string sysfsNodePath = sysfsNodePathChars.c_str(); + + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + im->getInputManager()->getReader().sysfsNodeChanged(sysfsNodePath); +} + static std::string dumpInputProperties() { std::string out = "Input properties:\n"; const std::string strategy = @@ -2565,6 +2587,12 @@ static jfloatArray nativeGetMouseCursorPosition(JNIEnv* env, jobject nativeImplO return outArr; } +static void nativeSetStylusPointerIconEnabled(JNIEnv* env, jobject nativeImplObj, + jboolean enabled) { + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + im->setStylusPointerIconEnabled(enabled); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { @@ -2631,6 +2659,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"getBatteryDevicePath", "(I)Ljava/lang/String;", (void*)nativeGetBatteryDevicePath}, {"reloadKeyboardLayouts", "()V", (void*)nativeReloadKeyboardLayouts}, {"reloadDeviceAliases", "()V", (void*)nativeReloadDeviceAliases}, + {"sysfsNodeChanged", "(Ljava/lang/String;)V", (void*)nativeSysfsNodeChanged}, {"dump", "()Ljava/lang/String;", (void*)nativeDump}, {"monitor", "()V", (void*)nativeMonitor}, {"isInputDeviceEnabled", "(I)Z", (void*)nativeIsInputDeviceEnabled}, @@ -2659,6 +2688,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"setStylusButtonMotionEventsEnabled", "(Z)V", (void*)nativeSetStylusButtonMotionEventsEnabled}, {"getMouseCursorPosition", "()[F", (void*)nativeGetMouseCursorPosition}, + {"setStylusPointerIconEnabled", "(Z)V", (void*)nativeSetStylusPointerIconEnabled}, }; #define FIND_CLASS(var, className) \ @@ -2819,9 +2849,6 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.isPerDisplayTouchModeEnabled, clazz, "isPerDisplayTouchModeEnabled", "()Z"); - GET_METHOD_ID(gServiceClassInfo.isStylusPointerIconEnabled, clazz, "isStylusPointerIconEnabled", - "()Z"); - // InputDevice FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java index 38dadc6b5b21..dce7b87c0328 100644 --- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java @@ -29,10 +29,6 @@ import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.util.Log; -import com.android.server.credentials.metrics.ApiName; -import com.android.server.credentials.metrics.ApiStatus; -import com.android.server.credentials.metrics.ProviderStatusForMetrics; - import java.util.ArrayList; /** @@ -40,7 +36,7 @@ import java.util.ArrayList; * responses from providers, and updates the provider(S) state. */ public final class ClearRequestSession extends RequestSession<ClearCredentialStateRequest, - IClearCredentialStateCallback> + IClearCredentialStateCallback, Void> implements ProviderSession.ProviderInternalCallback<Void> { private static final String TAG = "GetRequestSession"; @@ -50,7 +46,6 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta long startedTimestamp) { super(context, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED, callingAppInfo, cancellationSignal, startedTimestamp); - setupInitialPhaseMetric(ApiName.CLEAR_CREDENTIAL.getMetricCode(), MetricUtilities.ZERO); } /** @@ -77,7 +72,7 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta @Override // from provider session public void onProviderStatusChanged(ProviderSession.Status status, - ComponentName componentName) { + ComponentName componentName, ProviderSession.CredentialsSource source) { Log.i(TAG, "in onStatusChanged with status: " + status); if (ProviderSession.isTerminatingStatus(status)) { Log.i(TAG, "in onStatusChanged terminating status"); @@ -92,8 +87,10 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta public void onFinalResponseReceived( ComponentName componentName, Void response) { - setChosenMetric(componentName); - respondToClientWithResponseAndFinish(); + mRequestSessionMetric.collectChosenMetricViaCandidateTransfer( + mProviders.get(componentName.flattenToString()).mProviderSessionMetric + .getCandidatePhasePerProviderMetric()); + respondToClientWithResponseAndFinish(null); } protected void onProviderResponseComplete(ComponentName componentName) { @@ -114,55 +111,20 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta } @Override - public void onFinalErrorReceived(ComponentName componentName, String errorType, - String message) { - //Not applicable for clearCredential as response is not picked by the user + protected void invokeClientCallbackSuccess(Void response) throws RemoteException { + mClientCallback.onSuccess(); } - private void respondToClientWithResponseAndFinish() { - Log.i(TAG, "respondToClientWithResponseAndFinish"); - collectFinalPhaseMetricStatus(false, ProviderStatusForMetrics.FINAL_SUCCESS); - if (isSessionCancelled()) { - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.CLIENT_CANCELED.getMetricCode()); - finishSession(/*propagateCancellation=*/true); - return; - } - try { - mClientCallback.onSuccess(); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.SUCCESS.getMetricCode()); - } catch (RemoteException e) { - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - Log.i(TAG, "Issue while propagating the response to the client"); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.FAILURE.getMetricCode()); - } - finishSession(/*propagateCancellation=*/false); + @Override + protected void invokeClientCallbackError(String errorType, String errorMsg) + throws RemoteException { + mClientCallback.onError(errorType, errorMsg); } - private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { - Log.i(TAG, "respondToClientWithErrorAndFinish"); - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - if (isSessionCancelled()) { - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.CLIENT_CANCELED.getMetricCode()); - finishSession(/*propagateCancellation=*/true); - return; - } - try { - mClientCallback.onError(errorType, errorMsg); - } catch (RemoteException e) { - e.printStackTrace(); - } - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.FAILURE.getMetricCode()); - finishSession(/*propagateCancellation=*/false); + @Override + public void onFinalErrorReceived(ComponentName componentName, String errorType, + String message) { + //Not applicable for clearCredential as response is not picked by the user } private void processResponses() { @@ -170,7 +132,7 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta if (session.isProviderResponseSet()) { // If even one provider responded successfully, send back the response // TODO: Aggregate other exceptions - respondToClientWithResponseAndFinish(); + respondToClientWithResponseAndFinish(null); return; } } diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 687c86190fbd..98dc8ab8aa9c 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -35,8 +35,6 @@ import android.service.credentials.CallingAppInfo; import android.service.credentials.PermissionUtils; import android.util.Log; -import com.android.server.credentials.metrics.ApiName; -import com.android.server.credentials.metrics.ApiStatus; import com.android.server.credentials.metrics.ProviderStatusForMetrics; import java.util.ArrayList; @@ -47,7 +45,7 @@ import java.util.ArrayList; * provider(s) state maintained in {@link ProviderCreateSession}. */ public final class CreateRequestSession extends RequestSession<CreateCredentialRequest, - ICreateCredentialCallback> + ICreateCredentialCallback, CreateCredentialResponse> implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> { private static final String TAG = "CreateRequestSession"; @@ -59,7 +57,6 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR long startedTimestamp) { super(context, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE, callingAppInfo, cancellationSignal, startedTimestamp); - setupInitialPhaseMetric(ApiName.CREATE_CREDENTIAL.getMetricCode(), MetricUtilities.UNIT); } /** @@ -85,7 +82,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR @Override protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { - mChosenProviderFinalPhaseMetric.setUiCallStartTimeNanoseconds(System.nanoTime()); + mRequestSessionMetric.collectUiCallStartTime(System.nanoTime()); try { mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( RequestInfo.newCreateRequestInfo( @@ -95,7 +92,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)), providerDataList)); } catch (RemoteException e) { - mChosenProviderFinalPhaseMetric.setUiReturned(false); + mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); respondToClientWithErrorAndFinish( CreateCredentialException.TYPE_UNKNOWN, "Unable to invoke selector"); @@ -103,18 +100,31 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR } @Override + protected void invokeClientCallbackSuccess(CreateCredentialResponse response) + throws RemoteException { + mClientCallback.onResponse(response); + } + + @Override + protected void invokeClientCallbackError(String errorType, String errorMsg) + throws RemoteException { + mClientCallback.onError(errorType, errorMsg); + } + + @Override public void onFinalResponseReceived(ComponentName componentName, @Nullable CreateCredentialResponse response) { - mChosenProviderFinalPhaseMetric.setUiReturned(true); - mChosenProviderFinalPhaseMetric.setUiCallEndTimeNanoseconds(System.nanoTime()); Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString()); - setChosenMetric(componentName); + mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime()); + mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(mProviders.get( + componentName.flattenToString()).mProviderSessionMetric + .getCandidatePhasePerProviderMetric()); if (response != null) { - mChosenProviderFinalPhaseMetric.setChosenProviderStatus( + mRequestSessionMetric.collectChosenProviderStatus( ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode()); respondToClientWithResponseAndFinish(response); } else { - mChosenProviderFinalPhaseMetric.setChosenProviderStatus( + mRequestSessionMetric.collectChosenProviderStatus( ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode()); respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS, "Invalid response"); @@ -144,78 +154,9 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR "No create options available."); } - private void respondToClientWithResponseAndFinish(CreateCredentialResponse response) { - Log.i(TAG, "respondToClientWithResponseAndFinish"); - // TODO(b/271135048) - Improve Metrics super/sub class setup and emit. - collectFinalPhaseMetricStatus(false, ProviderStatusForMetrics.FINAL_SUCCESS); - if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); - return; - } - if (isSessionCancelled()) { - // TODO(b/271135048) - Migrate to superclass utilities (post beta1 cleanup) - applies - // for all - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.CLIENT_CANCELED.getMetricCode()); - finishSession(/*propagateCancellation=*/true); - return; - } - try { - mClientCallback.onResponse(response); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.SUCCESS.getMetricCode()); - } catch (RemoteException e) { - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - Log.i(TAG, "Issue while responding to client: " + e.getMessage()); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.FAILURE.getMetricCode()); - } - finishSession(/*propagateCancellation=*/false); - } - - private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { - Log.i(TAG, "respondToClientWithErrorAndFinish"); - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); - return; - } - if (isSessionCancelled()) { - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.CLIENT_CANCELED.getMetricCode()); - finishSession(/*propagateCancellation=*/true); - return; - } - try { - mClientCallback.onError(errorType, errorMsg); - } catch (RemoteException e) { - Log.i(TAG, "Issue while responding to client: " + e.getMessage()); - } - logFailureOrUserCancel(errorType); - finishSession(/*propagateCancellation=*/false); - } - - private void logFailureOrUserCancel(String errorType) { - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - if (CreateCredentialException.TYPE_USER_CANCELED.equals(errorType)) { - mChosenProviderFinalPhaseMetric.setHasException(false); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.USER_CANCELED.getMetricCode()); - } else { - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.FAILURE.getMetricCode()); - } - } - @Override public void onProviderStatusChanged(ProviderSession.Status status, - ComponentName componentName) { + ComponentName componentName, ProviderSession.CredentialsSource source) { Log.i(TAG, "in onProviderStatusChanged with status: " + status); // If all provider responses have been received, we can either need the UI, // or we need to respond with error. The only other case is the entry being diff --git a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java index 8ccc61b70f45..1164516b2eb8 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java +++ b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java @@ -25,19 +25,16 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; /** Contains information on what CredentialProvider has what provisioned Credential. */ public class CredentialDescriptionRegistry { - private static final String FLAT_STRING_SPLIT_REGEX = ";"; private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128; private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16; @GuardedBy("sLock") @@ -53,15 +50,15 @@ public class CredentialDescriptionRegistry { /** Represents the results of a given query into the registry. */ public static final class FilterResult { final String mPackageName; - final String mFlattenedRequest; + final Set<String> mElementKeys; final List<CredentialEntry> mCredentialEntries; @VisibleForTesting FilterResult(String packageName, - String flattenedRequest, + Set<String> elementKeys, List<CredentialEntry> credentialEntries) { mPackageName = packageName; - mFlattenedRequest = flattenedRequest; + mElementKeys = elementKeys; mCredentialEntries = credentialEntries; } } @@ -166,18 +163,17 @@ public class CredentialDescriptionRegistry { /** Returns package names and entries of a CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ public Set<FilterResult> getFilteredResultForProvider(String packageName, - String flatRequestString) { + Set<String> requestedKeyElements) { Set<FilterResult> result = new HashSet<>(); if (!mCredentialDescriptions.containsKey(packageName)) { return result; } Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName); - Set<String> unflattenedRequestString = flatStringToSet(flatRequestString); for (CredentialDescription containedDescription: currentSet) { - if (checkForMatch(flatStringToSet(containedDescription.getFlattenedRequestString()), - unflattenedRequestString)) { + if (checkForMatch(containedDescription.getSupportedElementKeys(), + requestedKeyElements)) { result.add(new FilterResult(packageName, - containedDescription.getFlattenedRequestString(), containedDescription + containedDescription.getSupportedElementKeys(), containedDescription .getCredentialEntries())); } } @@ -186,18 +182,15 @@ public class CredentialDescriptionRegistry { /** Returns package names of CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ - public Set<FilterResult> getMatchingProviders(Set<String> flatRequestStrings) { + public Set<FilterResult> getMatchingProviders(Set<Set<String>> supportedElementKeys) { Set<FilterResult> result = new HashSet<>(); - Set<Set<String>> unflattenedRequestStrings = flatRequestStrings.stream().map( - CredentialDescriptionRegistry::flatStringToSet).collect(Collectors.toSet()); for (String packageName: mCredentialDescriptions.keySet()) { Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName); for (CredentialDescription containedDescription : currentSet) { - if (canProviderSatisfyAny(flatStringToSet(containedDescription - .getFlattenedRequestString()), - unflattenedRequestStrings)) { + if (canProviderSatisfyAny(containedDescription.getSupportedElementKeys(), + supportedElementKeys)) { result.add(new FilterResult(packageName, - containedDescription.getFlattenedRequestString(), containedDescription + containedDescription.getSupportedElementKeys(), containedDescription .getCredentialEntries())); } } @@ -211,24 +204,19 @@ public class CredentialDescriptionRegistry { } } - private static boolean canProviderSatisfyAny(Set<String> registeredUnflattenedStrings, - Set<Set<String>> requestedUnflattenedStrings) { - for (Set<String> requestedUnflattenedString : requestedUnflattenedStrings) { - if (registeredUnflattenedStrings.containsAll(requestedUnflattenedString)) { + private static boolean canProviderSatisfyAny(Set<String> registeredElementKeys, + Set<Set<String>> requestedElementKeys) { + for (Set<String> requestedUnflattenedString : requestedElementKeys) { + if (registeredElementKeys.containsAll(requestedUnflattenedString)) { return true; } } return false; } - static boolean checkForMatch(Set<String> registeredUnflattenedStrings, - Set<String> requestedUnflattenedString) { - return registeredUnflattenedStrings.containsAll(requestedUnflattenedString); - } - - static Set<String> flatStringToSet(String flatString) { - return new HashSet<>(Arrays - .asList(flatString.split(FLAT_STRING_SPLIT_REGEX))); + static boolean checkForMatch(Set<String> registeredElementKeys, + Set<String> requestedElementKeys) { + return registeredElementKeys.containsAll(requestedElementKeys); } } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 90b92f43d80f..de06d440fa9d 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -160,12 +160,10 @@ public final class CredentialManagerService int resolvedUserId, boolean disabled, String[] serviceNames) { getOrConstructSystemServiceListLock(resolvedUserId); if (serviceNames == null || serviceNames.length == 0) { - Slog.i(TAG, "serviceNames sent in newServiceListLocked is null, or empty"); return new ArrayList<>(); } List<CredentialManagerServiceImpl> serviceList = new ArrayList<>(serviceNames.length); for (String serviceName : serviceNames) { - Log.i(TAG, "in newServiceListLocked, service: " + serviceName); if (TextUtils.isEmpty(serviceName)) { continue; } @@ -173,7 +171,7 @@ public final class CredentialManagerService serviceList.add( new CredentialManagerServiceImpl(this, mLock, resolvedUserId, serviceName)); } catch (PackageManager.NameNotFoundException | SecurityException e) { - Log.i(TAG, "Unable to add serviceInfo : " + e.getMessage()); + Slog.e(TAG, "Unable to add serviceInfo : ", e); } } return serviceList; @@ -339,13 +337,14 @@ public final class CredentialManagerService CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId()); // All requested credential descriptions based on the given request. - Set<String> requestedCredentialDescriptions = + Set<Set<String>> requestedCredentialDescriptions = options.stream() .map( getCredentialOption -> - getCredentialOption + new HashSet<>(getCredentialOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST)) + .getStringArrayList( + CredentialOption.SUPPORTED_ELEMENT_KEYS))) .collect(Collectors.toSet()); // All requested credential descriptions based on the given request. @@ -356,15 +355,13 @@ public final class CredentialManagerService new HashSet<>(); for (CredentialDescriptionRegistry.FilterResult filterResult : filterResults) { - Set<String> registeredUnflattenedStrings = CredentialDescriptionRegistry - .flatStringToSet(filterResult.mFlattenedRequest); for (CredentialOption credentialOption : options) { - Set<String> requestedUnflattenedStrings = CredentialDescriptionRegistry - .flatStringToSet(credentialOption + Set<String> requestedElementKeys = new HashSet<>( + credentialOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST)); - if (CredentialDescriptionRegistry.checkForMatch(registeredUnflattenedStrings, - requestedUnflattenedStrings)) { + .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); + if (CredentialDescriptionRegistry.checkForMatch(filterResult.mElementKeys, + requestedElementKeys)) { result.add(new Pair<>(credentialOption, filterResult)); } } @@ -424,7 +421,7 @@ public final class CredentialManagerService userId); callingAppInfo = new CallingAppInfo(realPackageName, packageInfo.signingInfo, origin); } catch (PackageManager.NameNotFoundException e) { - Log.i(TAG, "Issue while retrieving signatureInfo : " + e.getMessage()); + Slog.e(TAG, "Issue while retrieving signatureInfo : ", e); callingAppInfo = new CallingAppInfo(realPackageName, null, origin); } return callingAppInfo; @@ -437,19 +434,16 @@ public final class CredentialManagerService IGetCredentialCallback callback, final String callingPackage) { final long timestampBegan = System.nanoTime(); - Log.i(TAG, "starting executeGetCredential with callingPackage: " + callingPackage); + Slog.d(TAG, "starting executeGetCredential with callingPackage: " + + callingPackage); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); - if (request.getOrigin() != null) { - // Check privileged permissions - mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); - } - enforcePermissionForAllowedProviders(request); - final int userId = UserHandle.getCallingUserId(); final int callingUid = Binder.getCallingUid(); enforceCallingPackage(callingPackage, callingUid); + validateGetCredentialRequest(request); + // New request session, scoped for this request only. final GetRequestSession session = new GetRequestSession( @@ -462,7 +456,24 @@ public final class CredentialManagerService CancellationSignal.fromTransport(cancelTransport), timestampBegan); - processGetCredential(request, callback, session); + List<ProviderSession> providerSessions = + prepareProviderSessions(request, session); + + if (providerSessions.isEmpty()) { + try { + callback.onError( + GetCredentialException.TYPE_NO_CREDENTIAL, + "No credentials available on this device."); + } catch (RemoteException e) { + Log.i( + TAG, + "Issue invoking onError on IGetCredentialCallback " + + "callback: " + + e.getMessage()); + } + } + + invokeProviderSessions(providerSessions); return cancelTransport; } @@ -490,83 +501,22 @@ public final class CredentialManagerService getContext(), userId, callingUid, - prepareGetCredentialCallback, getCredentialCallback, request, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), CancellationSignal.fromTransport(cancelTransport), - timestampBegan); - - processGetCredential(request, prepareGetCredentialCallback, session); + timestampBegan, + prepareGetCredentialCallback); - return cancelTransport; - } - - private void processGetCredential( - GetCredentialRequest request, - IPrepareGetCredentialCallback callback, - PrepareGetRequestSession session) { - List<ProviderSession> providerSessions; - - if (isCredentialDescriptionApiEnabled()) { - List<CredentialOption> optionsThatRequireActiveCredentials = - request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - !TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) - .toList(); - - List<CredentialOption> optionsThatDoNotRequireActiveCredentials = - request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) - .toList(); - - List<ProviderSession> sessionsWithoutRemoteService = - initiateProviderSessionsWithActiveContainers( - session, - getFilteredResultFromRegistry(optionsThatRequireActiveCredentials)); - - List<ProviderSession> sessionsWithRemoteService = - initiateProviderSessions( - session, - optionsThatDoNotRequireActiveCredentials.stream() - .map(CredentialOption::getType) - .collect(Collectors.toList())); - - Set<ProviderSession> all = new LinkedHashSet<>(); - all.addAll(sessionsWithRemoteService); - all.addAll(sessionsWithoutRemoteService); - - providerSessions = new ArrayList<>(all); - } else { - // Initiate all provider sessions - providerSessions = - initiateProviderSessions( - session, - request.getCredentialOptions().stream() - .map(CredentialOption::getType) - .collect(Collectors.toList())); - } + List<ProviderSession> providerSessions = prepareProviderSessions(request, session); if (providerSessions.isEmpty()) { try { // TODO: fix - callback.onResponse(new PrepareGetCredentialResponseInternal( - false, null, false, false, null)); + prepareGetCredentialCallback.onResponse( + new PrepareGetCredentialResponseInternal( + false, null, + false, false, null)); } catch (RemoteException e) { Log.i( TAG, @@ -576,42 +526,33 @@ public final class CredentialManagerService } } - finalizeAndEmitInitialPhaseMetric(session); - // TODO(b/271135048) - May still be worth emitting in the empty cases above. - providerSessions.forEach(ProviderSession::invokeSession); + invokeProviderSessions(providerSessions); + + return cancelTransport; } - private void processGetCredential( + private List<ProviderSession> prepareProviderSessions( GetCredentialRequest request, - IGetCredentialCallback callback, GetRequestSession session) { List<ProviderSession> providerSessions; if (isCredentialDescriptionApiEnabled()) { List<CredentialOption> optionsThatRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - !TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) + .filter(credentialOption -> credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) != null) .toList(); List<CredentialOption> optionsThatDoNotRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) + .filter(credentialOption -> credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) == null) .toList(); List<ProviderSession> sessionsWithoutRemoteService = @@ -641,22 +582,12 @@ public final class CredentialManagerService .collect(Collectors.toList())); } - if (providerSessions.isEmpty()) { - try { - callback.onError( - GetCredentialException.TYPE_NO_CREDENTIAL, - "No credentials available on this device."); - } catch (RemoteException e) { - Log.i( - TAG, - "Issue invoking onError on IGetCredentialCallback " - + "callback: " - + e.getMessage()); - } - } - finalizeAndEmitInitialPhaseMetric(session); // TODO(b/271135048) - May still be worth emitting in the empty cases above. + return providerSessions; + } + + private void invokeProviderSessions(List<ProviderSession> providerSessions) { providerSessions.forEach(ProviderSession::invokeSession); } @@ -666,7 +597,7 @@ public final class CredentialManagerService ICreateCredentialCallback callback, String callingPackage) { final long timestampBegan = System.nanoTime(); - Log.i(TAG, "starting executeCreateCredential with callingPackage: " + Slog.d(TAG, "starting executeCreateCredential with callingPackage: " + callingPackage); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); @@ -709,11 +640,10 @@ public final class CredentialManagerService CreateCredentialException.TYPE_NO_CREATE_OPTIONS, "No create options available."); } catch (RemoteException e) { - Log.i( + Slog.e( TAG, "Issue invoking onError on ICreateCredentialCallback " - + "callback: " - + e.getMessage()); + + "callback: ", e); } } @@ -724,25 +654,24 @@ public final class CredentialManagerService private void finalizeAndEmitInitialPhaseMetric(RequestSession session) { try { - var initMetric = session.mInitialPhaseMetric; + var initMetric = session.mRequestSessionMetric.getInitialPhaseMetric(); initMetric.setCredentialServiceBeginQueryTimeNanoseconds(System.nanoTime()); - MetricUtilities.logApiCalled(initMetric, ++session.mSequenceCounter); + MetricUtilities.logApiCalledInitialPhase(initMetric, + session.mRequestSessionMetric.returnIncrementSequence()); } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + Log.w(TAG, "Unexpected error during metric logging: ", e); } } @Override public void setEnabledProviders( List<String> providers, int userId, ISetEnabledProvidersCallback callback) { - Log.i(TAG, "setEnabledProviders"); - if (!hasWriteSecureSettingsPermission()) { try { callback.onError( PERMISSION_DENIED_ERROR, PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR); } catch (RemoteException e) { - Log.e(TAG, "Issue with invoking response: " + e.getMessage()); + Slog.e(TAG, "Issue with invoking response: ", e); } return; } @@ -769,7 +698,7 @@ public final class CredentialManagerService "failed_setting_store", "Failed to store setting containing enabled providers"); } catch (RemoteException e) { - Log.i(TAG, "Issue with invoking error response: " + e.getMessage()); + Slog.e(TAG, "Issue with invoking error response: ", e); return; } } @@ -778,7 +707,7 @@ public final class CredentialManagerService try { callback.onResponse(); } catch (RemoteException e) { - Log.i(TAG, "Issue with invoking response: " + e.getMessage()); + Slog.e(TAG, "Issue with invoking response: ", e); // TODO: Propagate failure } @@ -790,7 +719,8 @@ public final class CredentialManagerService @Override public boolean isEnabledCredentialProviderService( ComponentName componentName, String callingPackage) { - Log.i(TAG, "isEnabledCredentialProviderService"); + Slog.d(TAG, "isEnabledCredentialProviderService with componentName: " + + componentName.flattenToString()); // TODO(253157366): Check additional set of services. final int userId = UserHandle.getCallingUserId(); @@ -805,16 +735,17 @@ public final class CredentialManagerService if (serviceComponentName.equals(componentName)) { if (!s.getServicePackageName().equals(callingPackage)) { // The component name and the package name do not match. - MetricUtilities.logApiCalled( + MetricUtilities.logApiCalledSimpleV1( ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, ApiStatus.FAILURE, callingUid); - Log.w( + Slog.w( TAG, - "isEnabledCredentialProviderService: Component name does not" - + " match package name."); + "isEnabledCredentialProviderService: Component name does " + + "not match package name."); return false; } - MetricUtilities.logApiCalled(ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, + MetricUtilities.logApiCalledSimpleV1( + ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, ApiStatus.SUCCESS, callingUid); // TODO(b/271135048) - Update asap to use the new logging types return true; @@ -828,7 +759,6 @@ public final class CredentialManagerService @Override public List<CredentialProviderInfo> getCredentialProviderServices( int userId, int providerFilter) { - Log.i(TAG, "getCredentialProviderServices"); verifyGetProvidersPermission(); return CredentialProviderInfoFactory.getCredentialProviderServices( @@ -838,7 +768,6 @@ public final class CredentialManagerService @Override public List<CredentialProviderInfo> getCredentialProviderServicesForTesting( int providerFilter) { - Log.i(TAG, "getCredentialProviderServicesForTesting"); verifyGetProvidersPermission(); final int userId = UserHandle.getCallingUserId(); @@ -859,8 +788,8 @@ public final class CredentialManagerService .getServiceInfo().getComponentName()); } catch (NullPointerException e) { // Safe check - Log.i(TAG, "Skipping provider as either the providerInfo" - + "or serviceInfo is null - weird"); + Slog.e(TAG, "Skipping provider as either the providerInfo" + + " or serviceInfo is null - weird"); } }); } @@ -873,7 +802,8 @@ public final class CredentialManagerService IClearCredentialStateCallback callback, String callingPackage) { final long timestampBegan = System.nanoTime(); - Log.i(TAG, "starting clearCredentialState with callingPackage: " + callingPackage); + Slog.d(TAG, "starting clearCredentialState with callingPackage: " + + callingPackage); final int userId = UserHandle.getCallingUserId(); int callingUid = Binder.getCallingUid(); enforceCallingPackage(callingPackage, callingUid); @@ -900,13 +830,13 @@ public final class CredentialManagerService if (providerSessions.isEmpty()) { try { // TODO("Replace with properly defined error type") - callback.onError("UNKNOWN", "No crdentials available on this " + "device"); + callback.onError("UNKNOWN", "No credentials available on " + + "this device"); } catch (RemoteException e) { - Log.i( + Slog.e( TAG, "Issue invoking onError on IClearCredentialStateCallback " - + "callback: " - + e.getMessage()); + + "callback: ", e); } } @@ -921,7 +851,7 @@ public final class CredentialManagerService public void registerCredentialDescription( RegisterCredentialDescriptionRequest request, String callingPackage) throws IllegalArgumentException, NonCredentialProviderCallerException { - Log.i(TAG, "registerCredentialDescription"); + Slog.d(TAG, "registerCredentialDescription with callingPackage: " + callingPackage); if (!isCredentialDescriptionApiEnabled()) { throw new UnsupportedOperationException(); @@ -939,7 +869,9 @@ public final class CredentialManagerService public void unregisterCredentialDescription( UnregisterCredentialDescriptionRequest request, String callingPackage) throws IllegalArgumentException { - Log.i(TAG, "registerCredentialDescription"); + Slog.d(TAG, "unregisterCredentialDescription with callingPackage: " + + callingPackage); + if (!isCredentialDescriptionApiEnabled()) { throw new UnsupportedOperationException(); @@ -954,6 +886,14 @@ public final class CredentialManagerService } } + private void validateGetCredentialRequest(GetCredentialRequest request) { + if (request.getOrigin() != null) { + // Check privileged permissions + mContext.enforceCallingPermission(CREDENTIAL_MANAGER_SET_ORIGIN, null); + } + enforcePermissionForAllowedProviders(request); + } + private void enforcePermissionForAllowedProviders(GetCredentialRequest request) { boolean containsAllowedProviders = request.getCredentialOptions() .stream() diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java index ee55a1ccc357..91be2a734e85 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java @@ -23,7 +23,6 @@ import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.credentials.CredentialProviderInfo; import android.service.credentials.CredentialProviderInfoFactory; -import android.util.Log; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -41,14 +40,15 @@ public final class CredentialManagerServiceImpl extends // TODO(b/210531) : Make final when update flow is fixed @GuardedBy("mLock") - @NonNull private CredentialProviderInfo mInfo; + @NonNull + private CredentialProviderInfo mInfo; CredentialManagerServiceImpl( @NonNull CredentialManagerService master, @NonNull Object lock, int userId, String serviceName) throws PackageManager.NameNotFoundException { super(master, lock, userId); - Log.i(TAG, "in CredentialManagerServiceImpl constructed with: " + serviceName); + Slog.d(TAG, "CredentialManagerServiceImpl constructed for: " + serviceName); synchronized (mLock) { newServiceInfoLocked(ComponentName.unflattenFromString(serviceName)); } @@ -63,10 +63,8 @@ public final class CredentialManagerServiceImpl extends @NonNull CredentialManagerService master, @NonNull Object lock, int userId, CredentialProviderInfo providerInfo) { super(master, lock, userId); - Log.i(TAG, "in CredentialManagerServiceImpl constructed with system constructor: " - + providerInfo.isSystemProvider() - + " , " + providerInfo.getServiceInfo() == null ? "" : - providerInfo.getServiceInfo().getComponentName().flattenToString()); + Slog.d(TAG, "CredentialManagerServiceImpl constructed for: " + + providerInfo.getServiceInfo().getComponentName().flattenToString()); mInfo = providerInfo; } @@ -76,12 +74,12 @@ public final class CredentialManagerServiceImpl extends throws PackageManager.NameNotFoundException { // TODO : Test update flows with multiple providers if (mInfo != null) { - Log.i(TAG, "newServiceInfoLocked with : " + Slog.d(TAG, "newServiceInfoLocked, mInfo not null : " + mInfo.getServiceInfo().getComponentName().flattenToString() + " , " - + serviceComponent.getPackageName()); + + serviceComponent.flattenToString()); } else { - Log.i(TAG, "newServiceInfoLocked with null mInfo , " - + serviceComponent.getPackageName()); + Slog.d(TAG, "newServiceInfoLocked, mInfo null, " + + serviceComponent.flattenToString()); } mInfo = CredentialProviderInfoFactory.create( getContext(), serviceComponent, @@ -90,18 +88,18 @@ public final class CredentialManagerServiceImpl extends } /** - * Starts a provider session and associates it with the given request session. */ + * Starts a provider session and associates it with the given request session. + */ @Nullable @GuardedBy("mLock") public ProviderSession initiateProviderSessionForRequestLocked( RequestSession requestSession, List<String> requestOptions) { if (!requestOptions.isEmpty() && !isServiceCapableLocked(requestOptions)) { - Log.i(TAG, "Service is not capable"); + Slog.d(TAG, "Service does not have the required capabilities"); return null; } - Slog.i(TAG, "in initiateProviderSessionForRequest in CredManServiceImpl"); if (mInfo == null) { - Slog.i(TAG, "in initiateProviderSessionForRequest in CredManServiceImpl, " + Slog.w(TAG, "in initiateProviderSessionForRequest in CredManServiceImpl, " + "but mInfo is null. This shouldn't happen"); return null; } @@ -114,15 +112,11 @@ public final class CredentialManagerServiceImpl extends @GuardedBy("mLock") boolean isServiceCapableLocked(List<String> requestedOptions) { if (mInfo == null) { - Slog.i(TAG, "in isServiceCapable, mInfo is null"); return false; } for (String capability : requestedOptions) { if (mInfo.hasCapability(capability)) { - Slog.i(TAG, "Provider can handle: " + capability); return true; - } else { - Slog.i(TAG, "Provider cannot handle: " + capability); } } return false; @@ -146,7 +140,7 @@ public final class CredentialManagerServiceImpl extends try { newServiceInfoLocked(mInfo.getServiceInfo().getComponentName()); } catch (PackageManager.NameNotFoundException e) { - Log.i(TAG, "Issue while updating serviceInfo: " + e.getMessage()); + Slog.e(TAG, "Issue while updating serviceInfo: " + e.getMessage()); } } } diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index 8082cdbf6ec8..c0c7be9d80e2 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -27,14 +27,11 @@ import android.credentials.GetCredentialResponse; import android.credentials.IGetCredentialCallback; import android.credentials.ui.ProviderData; import android.credentials.ui.RequestInfo; -import android.os.Binder; import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.util.Log; -import com.android.server.credentials.metrics.ApiName; -import com.android.server.credentials.metrics.ApiStatus; import com.android.server.credentials.metrics.ProviderStatusForMetrics; import java.util.ArrayList; @@ -45,7 +42,7 @@ import java.util.stream.Collectors; * responses from providers, and the UX app, and updates the provider(S) state. */ public class GetRequestSession extends RequestSession<GetCredentialRequest, - IGetCredentialCallback> + IGetCredentialCallback, GetCredentialResponse> implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> { private static final String TAG = "GetRequestSession"; public GetRequestSession(Context context, int userId, int callingUid, @@ -57,7 +54,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, int numTypes = (request.getCredentialOptions().stream() .map(CredentialOption::getType).collect( Collectors.toSet())).size(); // Dedupe type strings - setupInitialPhaseMetric(ApiName.GET_CREDENTIAL.getMetricCode(), numTypes); + mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes); } /** @@ -83,112 +80,58 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, @Override protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { - mChosenProviderFinalPhaseMetric.setUiCallStartTimeNanoseconds(System.nanoTime()); + mRequestSessionMetric.collectUiCallStartTime(System.nanoTime()); try { - Binder.withCleanCallingIdentity(() -> - mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( + mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( RequestInfo.newGetRequestInfo( mRequestId, mClientRequest, mClientAppInfo.getPackageName()), - providerDataList))); - } catch (RuntimeException e) { - mChosenProviderFinalPhaseMetric.setUiReturned(false); + providerDataList)); + } catch (RemoteException e) { + mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); respondToClientWithErrorAndFinish( GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector"); } } @Override + protected void invokeClientCallbackSuccess(GetCredentialResponse response) + throws RemoteException { + mClientCallback.onResponse(response); + } + + @Override + protected void invokeClientCallbackError(String errorType, String errorMsg) + throws RemoteException { + mClientCallback.onError(errorType, errorMsg); + } + + @Override public void onFinalResponseReceived(ComponentName componentName, @Nullable GetCredentialResponse response) { - mChosenProviderFinalPhaseMetric.setUiReturned(true); - mChosenProviderFinalPhaseMetric.setUiCallEndTimeNanoseconds(System.nanoTime()); Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString()); - setChosenMetric(componentName); + mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime()); + mRequestSessionMetric.collectChosenMetricViaCandidateTransfer( + mProviders.get(componentName.flattenToString()) + .mProviderSessionMetric.getCandidatePhasePerProviderMetric()); if (response != null) { - mChosenProviderFinalPhaseMetric.setChosenProviderStatus( + mRequestSessionMetric.collectChosenProviderStatus( ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode()); respondToClientWithResponseAndFinish(response); } else { - mChosenProviderFinalPhaseMetric.setChosenProviderStatus( + mRequestSessionMetric.collectChosenProviderStatus( ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode()); respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, "Invalid response from provider"); } } - //TODO: Try moving the three error & response methods below to RequestSession to be shared - // between get & create. + //TODO(b/274954697): Further shorten the three below to completely migrate to superclass @Override public void onFinalErrorReceived(ComponentName componentName, String errorType, String message) { respondToClientWithErrorAndFinish(errorType, message); } - private void respondToClientWithResponseAndFinish(GetCredentialResponse response) { - collectFinalPhaseMetricStatus(false, ProviderStatusForMetrics.FINAL_SUCCESS); - if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); - return; - } - if (isSessionCancelled()) { - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.CLIENT_CANCELED.getMetricCode()); - finishSession(/*propagateCancellation=*/true); - return; - } - try { - mClientCallback.onResponse(response); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.SUCCESS.getMetricCode()); - } catch (RemoteException e) { - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - Log.i(TAG, "Issue while responding to client with a response : " + e.getMessage()); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.FAILURE.getMetricCode()); - } - finishSession(/*propagateCancellation=*/false); - } - - private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); - return; - } - if (isSessionCancelled()) { - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.CLIENT_CANCELED.getMetricCode()); - finishSession(/*propagateCancellation=*/true); - return; - } - - try { - mClientCallback.onError(errorType, errorMsg); - } catch (RemoteException e) { - Log.i(TAG, "Issue while responding to client with error : " + e.getMessage()); - } - logFailureOrUserCancel(errorType); - finishSession(/*propagateCancellation=*/false); - } - - private void logFailureOrUserCancel(String errorType) { - collectFinalPhaseMetricStatus(true, ProviderStatusForMetrics.FINAL_FAILURE); - if (GetCredentialException.TYPE_USER_CANCELED.equals(errorType)) { - mChosenProviderFinalPhaseMetric.setHasException(false); - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.USER_CANCELED.getMetricCode()); - } else { - logApiCall(mChosenProviderFinalPhaseMetric, - mCandidateBrowsingPhaseMetric, - /* apiStatus */ ApiStatus.FAILURE.getMetricCode()); - } - } - @Override public void onUiCancellation(boolean isUserCancellation) { if (isUserCancellation) { @@ -208,8 +151,9 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, @Override public void onProviderStatusChanged(ProviderSession.Status status, - ComponentName componentName) { - Log.i(TAG, "in onStatusChanged with status: " + status); + ComponentName componentName, ProviderSession.CredentialsSource source) { + Log.i(TAG, "in onStatusChanged with status: " + status + "and source: " + source); + // Auth entry was selected, and it did not have any underlying credentials if (status == ProviderSession.Status.NO_CREDENTIALS_FROM_AUTH_ENTRY) { handleEmptyAuthenticationSelection(componentName); @@ -230,7 +174,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, } } - private void handleEmptyAuthenticationSelection(ComponentName componentName) { + protected void handleEmptyAuthenticationSelection(ComponentName componentName) { // Update auth entry statuses across different provider sessions mProviders.keySet().forEach(key -> { ProviderGetSession session = (ProviderGetSession) mProviders.get(key); diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index 65fb3681d24d..c48654a9fce7 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -37,8 +37,10 @@ import java.util.Map; * from {@link com.android.internal.util.FrameworkStatsLog}. */ public class MetricUtilities { + private static final boolean LOG_FLAG = true; private static final String TAG = "MetricUtilities"; + public static final String USER_CANCELED_SUBSTRING = "TYPE_USER_CANCELED"; public static final int DEFAULT_INT_32 = -1; public static final int[] DEFAULT_REPEATED_INT_32 = new int[0]; @@ -90,10 +92,13 @@ public class MetricUtilities { * @param apiStatus the final status of this particular api call * @param emitSequenceId an emitted sequence id for the current session */ - protected static void logApiCalled(ChosenProviderFinalPhaseMetric finalPhaseMetric, + public static void logApiCalledFinalPhase(ChosenProviderFinalPhaseMetric finalPhaseMetric, List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus, int emitSequenceId) { try { + if (!LOG_FLAG) { + return; + } int browsedSize = browsingPhaseMetrics.size(); int[] browsedClickedEntries = new int[browsedSize]; int[] browsedProviderUid = new int[browsedSize]; @@ -151,9 +156,12 @@ public class MetricUtilities { * @param providers a map with known providers and their held metric objects * @param emitSequenceId an emitted sequence id for the current session */ - protected static void logApiCalled(Map<String, ProviderSession> providers, + public static void logApiCalledCandidatePhase(Map<String, ProviderSession> providers, int emitSequenceId) { try { + if (!LOG_FLAG) { + return; + } var providerSessions = providers.values(); int providerSize = providerSessions.size(); int sessionId = -1; @@ -171,7 +179,8 @@ public class MetricUtilities { int[] candidateRemoteEntryCountList = new int[providerSize]; int index = 0; for (var session : providerSessions) { - CandidatePhaseMetric metric = session.mCandidatePhasePerProviderMetric; + CandidatePhaseMetric metric = session.mProviderSessionMetric + .getCandidatePhasePerProviderMetric(); if (sessionId == -1) { sessionId = metric.getSessionId(); } @@ -225,14 +234,18 @@ public class MetricUtilities { * contain default values for all other optional parameters. * * TODO(b/271135048) - given space requirements, this may be a good candidate for another atom + * TODO immediately remove and carry over TODO to new log for this setup * * @param apiName the api name to log * @param apiStatus the status to log * @param callingUid the calling uid */ - protected static void logApiCalled(ApiName apiName, ApiStatus apiStatus, + public static void logApiCalledSimpleV1(ApiName apiName, ApiStatus apiStatus, int callingUid) { try { + if (!LOG_FLAG) { + return; + } FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED, /* api_name */apiName.getMetricCode(), /* caller_uid */ callingUid, @@ -258,8 +271,12 @@ public class MetricUtilities { * @param initialPhaseMetric contains all the data for this emit * @param sequenceNum the sequence number for this api call session emit */ - protected static void logApiCalled(InitialPhaseMetric initialPhaseMetric, int sequenceNum) { + public static void logApiCalledInitialPhase(InitialPhaseMetric initialPhaseMetric, + int sequenceNum) { try { + if (!LOG_FLAG) { + return; + } FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_INIT_PHASE, /* api_name */ initialPhaseMetric.getApiName(), /* caller_uid */ initialPhaseMetric.getCallerUid(), @@ -275,5 +292,4 @@ public class MetricUtilities { Log.w(TAG, "Unexpected error during metric logging: " + e); } } - } diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java index f48fc2c37aff..c4e480a8e609 100644 --- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,7 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.credentials.CredentialOption; -import android.credentials.CredentialProviderInfo; -import android.credentials.GetCredentialException; import android.credentials.GetCredentialRequest; -import android.credentials.GetCredentialResponse; import android.credentials.IGetCredentialCallback; import android.credentials.IPrepareGetCredentialCallback; import android.credentials.PrepareGetCredentialResponseInternal; @@ -37,227 +34,83 @@ import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.service.credentials.PermissionUtils; import android.util.Log; - -import com.android.server.credentials.metrics.ApiName; -import com.android.server.credentials.metrics.ProviderStatusForMetrics; +import android.util.Slog; import java.util.ArrayList; import java.util.Set; import java.util.stream.Collectors; /** - * Central session for a single prepareGetCredentials request. This class listens to the - * responses from providers, and the UX app, and updates the provider(S) state. + * Central session for a single pendingGetCredential request. This class listens to the + * responses from providers, and the UX app, and updates the provider(s) state. */ -public class PrepareGetRequestSession extends RequestSession<GetCredentialRequest, - IGetCredentialCallback> - implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> { - private static final String TAG = "GetRequestSession"; +public class PrepareGetRequestSession extends GetRequestSession { + private static final String TAG = "PrepareGetRequestSession"; private final IPrepareGetCredentialCallback mPrepareGetCredentialCallback; - private boolean mIsInitialQuery = true; public PrepareGetRequestSession(Context context, int userId, int callingUid, - IPrepareGetCredentialCallback prepareGetCredentialCallback, - IGetCredentialCallback getCredCallback, GetCredentialRequest request, - CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal, - long startedTimestamp) { - super(context, userId, callingUid, request, getCredCallback, RequestInfo.TYPE_GET, - callingAppInfo, cancellationSignal, startedTimestamp); + IGetCredentialCallback callback, + GetCredentialRequest request, + CallingAppInfo callingAppInfo, + CancellationSignal cancellationSignal, long startedTimestamp, + IPrepareGetCredentialCallback prepareGetCredentialCallback) { + super(context, userId, callingUid, callback, request, callingAppInfo, cancellationSignal, + startedTimestamp); int numTypes = (request.getCredentialOptions().stream() .map(CredentialOption::getType).collect( Collectors.toSet())).size(); // Dedupe type strings - setupInitialPhaseMetric(ApiName.GET_CREDENTIAL.getMetricCode(), numTypes); + mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes); mPrepareGetCredentialCallback = prepareGetCredentialCallback; } - /** - * Creates a new provider session, and adds it list of providers that are contributing to - * this session. - * - * @return the provider session created within this request session, for the given provider - * info. - */ - @Override - @Nullable - public ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo, - RemoteCredentialService remoteCredentialService) { - ProviderGetSession providerGetSession = ProviderGetSession - .createNewSession(mContext, mUserId, providerInfo, - this, remoteCredentialService); - if (providerGetSession != null) { - Log.i(TAG, "In startProviderSession - provider session created and being added"); - mProviders.put(providerGetSession.getComponentName().flattenToString(), - providerGetSession); - } - return providerGetSession; - } - - @Override - protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { - mChosenProviderFinalPhaseMetric.setUiCallStartTimeNanoseconds(System.nanoTime()); - try { - mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( - RequestInfo.newGetRequestInfo( - mRequestId, mClientRequest, mClientAppInfo.getPackageName()), - providerDataList)); - } catch (RemoteException e) { - mChosenProviderFinalPhaseMetric.setUiReturned(false); - respondToClientWithErrorAndFinish( - GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector"); - } - } - - @Override - public void onFinalResponseReceived(ComponentName componentName, - @Nullable GetCredentialResponse response) { - mChosenProviderFinalPhaseMetric.setUiReturned(true); - mChosenProviderFinalPhaseMetric.setUiCallEndTimeNanoseconds(System.nanoTime()); - Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString()); - setChosenMetric(componentName); - if (response != null) { - mChosenProviderFinalPhaseMetric.setChosenProviderStatus( - ProviderStatusForMetrics.FINAL_SUCCESS.getMetricCode()); - respondToClientWithResponseAndFinish(response); - } else { - mChosenProviderFinalPhaseMetric.setChosenProviderStatus( - ProviderStatusForMetrics.FINAL_FAILURE.getMetricCode()); - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, - "Invalid response from provider"); - } - } - - //TODO: Try moving the three error & response methods below to RequestSession to be shared - // between get & create. @Override - public void onFinalErrorReceived(ComponentName componentName, String errorType, - String message) { - respondToClientWithErrorAndFinish(errorType, message); - } - - private void respondToClientWithResponseAndFinish(GetCredentialResponse response) { - if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); - return; - } - if (isSessionCancelled()) { -// TODO: properly log the new api -// logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ -// ApiStatus.CLIENT_CANCELED); - finishSession(/*propagateCancellation=*/true); - return; - } - try { - mClientCallback.onResponse(response); -// TODO: properly log the new api -// logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ -// ApiStatus.SUCCESS); - } catch (RemoteException e) { - Log.i(TAG, "Issue while responding to client with a response : " + e.getMessage()); -// TODO: properly log the new api -// logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ -// ApiStatus.FAILURE); - } - finishSession(/*propagateCancellation=*/false); - } - - private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { - if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); - return; - } - if (isSessionCancelled()) { -// TODO: properly log the new api -// logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ -// ApiStatus.CLIENT_CANCELED); - finishSession(/*propagateCancellation=*/true); - return; - } - - try { - mClientCallback.onError(errorType, errorMsg); - } catch (RemoteException e) { - Log.i(TAG, "Issue while responding to client with error : " + e.getMessage()); - } - logFailureOrUserCancel(errorType); - finishSession(/*propagateCancellation=*/false); - } - - private void logFailureOrUserCancel(String errorType) { - if (GetCredentialException.TYPE_USER_CANCELED.equals(errorType)) { -// TODO: properly log the new api -// logApiCall(ApiName.GET_CREDENTIAL, -// /* apiStatus */ ApiStatus.USER_CANCELED); - } else { -// TODO: properly log the new api -// logApiCall(ApiName.GET_CREDENTIAL, -// /* apiStatus */ ApiStatus.FAILURE); - } - } - - @Override - public void onUiCancellation(boolean isUserCancellation) { - if (isUserCancellation) { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_USER_CANCELED, - "User cancelled the selector"); - } else { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_INTERRUPTED, - "The UI was interrupted - please try again."); - } - } - - @Override - public void onUiSelectorInvocationFailure() { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, - "No credentials available."); - } - - @Override - public void onProviderStatusChanged(ProviderSession.Status status, - ComponentName componentName) { - Log.i(TAG, "in onStatusChanged with status: " + status); - // Auth entry was selected, and it did not have any underlying credentials - if (status == ProviderSession.Status.NO_CREDENTIALS_FROM_AUTH_ENTRY) { - handleEmptyAuthenticationSelection(componentName); - return; - } - // For any other status, we check if all providers are done and then invoke UI if needed - if (!isAnyProviderPending()) { - // If all provider responses have been received, we can either need the UI, - // or we need to respond with error. The only other case is the entry being - // selected after the UI has been invoked which has a separate code path. - if (mIsInitialQuery) { - // First time in this state. UI shouldn't be invoked because developer wants to - // punt it for later + public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName, + ProviderSession.CredentialsSource source) { + switch (source) { + case REMOTE_PROVIDER: + // Remote provider's status changed. We should check if all providers are done, and + // if UI invocation is needed. + if (isAnyProviderPending()) { + // Waiting for a remote provider response + return; + } boolean hasQueryCandidatePermission = PermissionUtils.hasPermission( mContext, mClientAppInfo.getPackageName(), Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS); if (isUiInvocationNeeded()) { + // To avoid extra computation, we only prepare the data at this point when we + // know that UI invocation is needed ArrayList<ProviderData> providerData = getProviderDataForUi(); if (!providerData.isEmpty()) { constructPendingResponseAndInvokeCallback(hasQueryCandidatePermission, getCredentialResultTypes(hasQueryCandidatePermission), - hasAuthenticationResults(providerData, hasQueryCandidatePermission), + hasAuthenticationResults(providerData, + hasQueryCandidatePermission), hasRemoteResults(providerData, hasQueryCandidatePermission), getUiIntent()); - } else { - constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission); + return; } - } else { - constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission); } - mIsInitialQuery = false; - } else { - // Not the first time. This could be a result of a user selection leading to a UI - // invocation again. - if (isUiInvocationNeeded()) { + // We reach here if Ui invocation is not needed, or provider data is empty + constructEmptyPendingResponseAndInvokeCallback( + hasQueryCandidatePermission); + break; + + case AUTH_ENTRY: + // Status updated through a selected authentication entry. We don't need to + // check on any other credential source and can process this result directly. + if (status == ProviderSession.Status.NO_CREDENTIALS_FROM_AUTH_ENTRY) { + // Update entry subtitle and re-invoke UI + super.handleEmptyAuthenticationSelection(componentName); + } else if (status == ProviderSession.Status.CREDENTIALS_RECEIVED) { getProviderDataAndInitiateUi(); - } else { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, - "No credentials available"); } - } + break; + default: + Slog.w(TAG, "Unexpected source"); + break; } } @@ -342,34 +195,4 @@ public class PrepareGetRequestSession extends RequestSession<GetCredentialReques return null; } } - - private void handleEmptyAuthenticationSelection(ComponentName componentName) { - // Update auth entry statuses across different provider sessions - mProviders.keySet().forEach(key -> { - ProviderGetSession session = (ProviderGetSession) mProviders.get(key); - if (!session.mComponentName.equals(componentName)) { - session.updateAuthEntriesStatusFromAnotherSession(); - } - }); - - // Invoke UI since it needs to show a snackbar if last auth entry, or a status on each - // auth entries along with other valid entries - getProviderDataAndInitiateUi(); - - // Respond to client if all auth entries are empty and nothing else to show on the UI - if (providerDataContainsEmptyAuthEntriesOnly()) { - respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, - "No credentials available"); - } - } - - private boolean providerDataContainsEmptyAuthEntriesOnly() { - for (String key : mProviders.keySet()) { - ProviderGetSession session = (ProviderGetSession) mProviders.get(key); - if (!session.containsEmptyAuthEntriesOnly()) { - return false; - } - } - return true; - } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java index 69a642d87ff6..1b736e01c842 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java @@ -82,7 +82,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS public void onProviderResponseSuccess(@Nullable Void response) { Log.i(TAG, "in onProviderResponseSuccess"); mProviderResponseSet = true; - updateStatusAndInvokeCallback(Status.COMPLETE); + updateStatusAndInvokeCallback(Status.COMPLETE, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } /** Called when the provider response resulted in a failure. */ @@ -91,15 +92,17 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS if (exception instanceof ClearCredentialStateException) { mProviderException = (ClearCredentialStateException) exception; } - captureCandidateFailureInMetrics(); - updateStatusAndInvokeCallback(toStatus(errorCode)); + mProviderSessionMetric.collectCandidateExceptionStatus(/*hasException=*/true); + updateStatusAndInvokeCallback(toStatus(errorCode), + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } /** Called when provider service dies. */ @Override // Callback from the remote provider public void onProviderServiceDied(RemoteCredentialService service) { if (service.getComponentName().equals(mComponentName)) { - updateStatusAndInvokeCallback(Status.SERVICE_DEAD); + updateStatusAndInvokeCallback(Status.SERVICE_DEAD, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } else { Slog.i(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java index 2ba9c226f5b4..bef045f8f890 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java @@ -40,8 +40,6 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; -import com.android.server.credentials.metrics.EntryEnum; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -158,15 +156,17 @@ public final class ProviderCreateSession extends ProviderSession< // Store query phase exception for aggregation with final response mProviderException = (CreateCredentialException) exception; } - captureCandidateFailureInMetrics(); - updateStatusAndInvokeCallback(toStatus(errorCode)); + mProviderSessionMetric.collectCandidateExceptionStatus(/*hasException=*/true); + updateStatusAndInvokeCallback(toStatus(errorCode), + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } /** Called when provider service dies. */ @Override public void onProviderServiceDied(RemoteCredentialService service) { if (service.getComponentName().equals(mComponentName)) { - updateStatusAndInvokeCallback(Status.SERVICE_DEAD); + updateStatusAndInvokeCallback(Status.SERVICE_DEAD, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } else { Slog.i(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); @@ -179,34 +179,13 @@ public final class ProviderCreateSession extends ProviderSession< mProviderResponseDataHandler.addResponseContent(response.getCreateEntries(), response.getRemoteCreateEntry()); if (mProviderResponseDataHandler.isEmptyResponse(response)) { - gatherCandidateEntryMetrics(response); - updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE); + mProviderSessionMetric.collectCandidateEntryMetrics(response); + updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } else { - gatherCandidateEntryMetrics(response); - updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED); - } - } - - private void gatherCandidateEntryMetrics(BeginCreateCredentialResponse response) { - try { - var createEntries = response.getCreateEntries(); - int numRemoteEntry = MetricUtilities.ZERO; - if (response.getRemoteCreateEntry() != null) { - numRemoteEntry = MetricUtilities.UNIT; - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY); - } - int numCreateEntries = - createEntries == null ? MetricUtilities.ZERO : createEntries.size(); - if (numCreateEntries > MetricUtilities.ZERO) { - createEntries.forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY)); - } - mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCreateEntries + numRemoteEntry); - mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry); - mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCreateEntries); - mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(MetricUtilities.UNIT); - } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + mProviderSessionMetric.collectCandidateEntryMetrics(response); + updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 7d3c86b3ad12..427a8945c573 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -43,8 +43,6 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; -import com.android.server.credentials.metrics.EntryEnum; - import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -52,7 +50,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; /** * Central provider session that listens for provider callbacks, and maintains provider state. @@ -121,41 +118,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return null; } - /** Creates a new provider session to be used by the request session. */ - @Nullable - public static ProviderGetSession createNewSession( - Context context, - @UserIdInt int userId, - CredentialProviderInfo providerInfo, - PrepareGetRequestSession getRequestSession, - RemoteCredentialService remoteCredentialService) { - android.credentials.GetCredentialRequest filteredRequest = - filterOptions(providerInfo.getCapabilities(), - getRequestSession.mClientRequest, - providerInfo); - if (filteredRequest != null) { - Map<String, CredentialOption> beginGetOptionToCredentialOptionMap = - new HashMap<>(); - return new ProviderGetSession( - context, - providerInfo, - getRequestSession, - userId, - remoteCredentialService, - constructQueryPhaseRequest( - filteredRequest, getRequestSession.mClientAppInfo, - getRequestSession.mClientRequest.alwaysSendAppInfoToProvider(), - beginGetOptionToCredentialOptionMap), - filteredRequest, - getRequestSession.mClientAppInfo, - beginGetOptionToCredentialOptionMap, - getRequestSession.mHybridService - ); - } - Log.i(TAG, "Unable to create provider session"); - return null; - } - private static BeginGetCredentialRequest constructQueryPhaseRequest( android.credentials.GetCredentialRequest filteredRequest, CallingAppInfo callingAppInfo, @@ -256,15 +218,17 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential if (exception instanceof GetCredentialException) { mProviderException = (GetCredentialException) exception; } - captureCandidateFailureInMetrics(); - updateStatusAndInvokeCallback(toStatus(errorCode)); + mProviderSessionMetric.collectCandidateExceptionStatus(/*hasException=*/true); + updateStatusAndInvokeCallback(toStatus(errorCode), + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } /** Called when provider service dies. */ @Override // Callback from the remote provider public void onProviderServiceDied(RemoteCredentialService service) { if (service.getComponentName().equals(mComponentName)) { - updateStatusAndInvokeCallback(Status.SERVICE_DEAD); + updateStatusAndInvokeCallback(Status.SERVICE_DEAD, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } else { Slog.i(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); @@ -309,13 +273,15 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential Log.i(TAG, "Additional content received - removing authentication entry"); mProviderResponseDataHandler.removeAuthenticationAction(entryKey); if (!mProviderResponseDataHandler.isEmptyResponse()) { - updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED); + updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED, + /*source=*/ CredentialsSource.AUTH_ENTRY); } } else { Log.i(TAG, "Additional content not received"); mProviderResponseDataHandler .updateAuthEntryWithNoCredentialsReceived(entryKey); - updateStatusAndInvokeCallback(Status.NO_CREDENTIALS_FROM_AUTH_ENTRY); + updateStatusAndInvokeCallback(Status.NO_CREDENTIALS_FROM_AUTH_ENTRY, + /*source=*/ CredentialsSource.AUTH_ENTRY); } break; case REMOTE_ENTRY_KEY: @@ -502,42 +468,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential addToInitialRemoteResponse(response, /*isInitialResponse=*/true); // Log the data. if (mProviderResponseDataHandler.isEmptyResponse(response)) { - updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE); + mProviderSessionMetric.collectCandidateEntryMetrics(response); + updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); return; } - gatherCandidateEntryMetrics(response); - updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED); - } - - private void gatherCandidateEntryMetrics(BeginGetCredentialResponse response) { - try { - int numCredEntries = response.getCredentialEntries().size(); - int numActionEntries = response.getActions().size(); - int numAuthEntries = response.getAuthenticationActions().size(); - int numRemoteEntry = MetricUtilities.ZERO; - if (response.getRemoteCredentialEntry() != null) { - numRemoteEntry = MetricUtilities.UNIT; - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY); - } - response.getCredentialEntries().forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY)); - response.getActions().forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.ACTION_ENTRY)); - response.getAuthenticationActions().forEach(c -> - mCandidatePhasePerProviderMetric.addEntry(EntryEnum.AUTHENTICATION_ENTRY)); - mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCredEntries + numAuthEntries - + numActionEntries + numRemoteEntry); - mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCredEntries); - int numTypes = (response.getCredentialEntries().stream() - .map(CredentialEntry::getType).collect( - Collectors.toSet())).size(); // Dedupe type strings - mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(numTypes); - mCandidatePhasePerProviderMetric.setActionEntryCount(numActionEntries); - mCandidatePhasePerProviderMetric.setAuthenticationEntryCount(numAuthEntries); - mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry); - } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); - } + mProviderSessionMetric.collectCandidateEntryMetrics(response); + updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED, + /*source=*/ CredentialsSource.REMOTE_PROVIDER); } /** diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java index 85c78445e66b..9cf27210dde0 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java @@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -103,7 +104,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption @NonNull private final String mCredentialProviderPackageName; @NonNull - private final String mFlattenedRequestOptionString; + private final Set<String> mElementKeys; @VisibleForTesting List<CredentialEntry> mCredentialEntries; @@ -119,9 +120,9 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId); mCallingAppInfo = callingAppInfo; mCredentialProviderPackageName = servicePackageName; - mFlattenedRequestOptionString = requestOption + mElementKeys = new HashSet<>(requestOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST); + .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); } protected ProviderRegistryGetSession(@NonNull Context context, @@ -136,9 +137,9 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId); mCallingAppInfo = callingAppInfo; mCredentialProviderPackageName = servicePackageName; - mFlattenedRequestOptionString = requestOption + mElementKeys = new HashSet<>(requestOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST); + .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); } private List<Entry> prepareUiCredentialEntries( @@ -257,13 +258,14 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption protected void invokeSession() { mProviderResponse = mCredentialDescriptionRegistry .getFilteredResultForProvider(mCredentialProviderPackageName, - mFlattenedRequestOptionString); + mElementKeys); mCredentialEntries = mProviderResponse.stream().flatMap( (Function<CredentialDescriptionRegistry.FilterResult, Stream<CredentialEntry>>) filterResult -> filterResult.mCredentialEntries.stream()) .collect(Collectors.toList()); - updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED); + updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED, + /*source=*/ CredentialsSource.REGISTRY); // TODO(use metric later) } diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java index 64ac9b3b4b94..8c0e1c1511e6 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java @@ -31,9 +31,7 @@ import android.os.ICancellationSignal; import android.os.RemoteException; import android.util.Log; -import com.android.server.credentials.metrics.CandidatePhaseMetric; -import com.android.server.credentials.metrics.InitialPhaseMetric; -import com.android.server.credentials.metrics.ProviderStatusForMetrics; +import com.android.server.credentials.metrics.ProviderSessionMetric; import java.util.UUID; @@ -72,13 +70,17 @@ public abstract class ProviderSession<T, R> protected R mProviderResponse; @NonNull protected Boolean mProviderResponseSet = false; - // Specific candidate provider metric for the provider this session handles @NonNull - protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric = - new CandidatePhaseMetric(); + protected final ProviderSessionMetric mProviderSessionMetric = new ProviderSessionMetric(); @NonNull private int mProviderSessionUid; + enum CredentialsSource { + REMOTE_PROVIDER, + REGISTRY, + AUTH_ENTRY + } + /** * Returns true if the given status reflects that the provider state is ready to be shown * on the credMan UI. @@ -122,7 +124,8 @@ public abstract class ProviderSession<T, R> */ public interface ProviderInternalCallback<V> { /** Called when status changes. */ - void onProviderStatusChanged(Status status, ComponentName componentName); + void onProviderStatusChanged(Status status, ComponentName componentName, + CredentialsSource source); /** Called when the final credential is received through an entry selection. */ void onFinalResponseReceived(ComponentName componentName, V response); @@ -209,49 +212,19 @@ public abstract class ProviderSession<T, R> return mRemoteCredentialService; } - protected void captureCandidateFailureInMetrics() { - mCandidatePhasePerProviderMetric.setHasException(true); - } - /** Updates the status . */ - protected void updateStatusAndInvokeCallback(@NonNull Status status) { + protected void updateStatusAndInvokeCallback(@NonNull Status status, + CredentialsSource source) { setStatus(status); - updateCandidateMetric(status); - mCallbacks.onProviderStatusChanged(status, mComponentName); + mProviderSessionMetric.collectCandidateMetricUpdate(isTerminatingStatus(status), + isCompletionStatus(status), mProviderSessionUid); + mCallbacks.onProviderStatusChanged(status, mComponentName, source); } - private void updateCandidateMetric(Status status) { - try { - mCandidatePhasePerProviderMetric.setCandidateUid(mProviderSessionUid); - mCandidatePhasePerProviderMetric - .setQueryFinishTimeNanoseconds(System.nanoTime()); - if (isTerminatingStatus(status)) { - mCandidatePhasePerProviderMetric.setQueryReturned(false); - mCandidatePhasePerProviderMetric.setProviderQueryStatus( - ProviderStatusForMetrics.QUERY_FAILURE - .getMetricCode()); - } else if (isCompletionStatus(status)) { - mCandidatePhasePerProviderMetric.setQueryReturned(true); - mCandidatePhasePerProviderMetric.setProviderQueryStatus( - ProviderStatusForMetrics.QUERY_SUCCESS - .getMetricCode()); - } - } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); - } - } - - // Common method to transfer metrics from the initial phase to the candidate phase per provider + /** Common method that transfers metrics from the init phase to candidates */ protected void startCandidateMetrics() { - try { - InitialPhaseMetric initMetric = ((RequestSession) mCallbacks).mInitialPhaseMetric; - mCandidatePhasePerProviderMetric.setSessionId(initMetric.getSessionId()); - mCandidatePhasePerProviderMetric.setServiceBeganTimeNanoseconds( - initMetric.getCredentialServiceStartedTimeNanoseconds()); - mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); - } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); - } + mProviderSessionMetric.collectCandidateMetricSetupViaInitialMetric( + ((RequestSession) mCallbacks).mRequestSessionMetric.getInitialPhaseMetric()); } /** Get the request to be sent to the provider. */ diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index d4ad65e5b567..cfb9ad46812d 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -16,8 +16,6 @@ package com.android.server.credentials; -import static com.android.server.credentials.MetricUtilities.logApiCalled; - import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ComponentName; @@ -30,27 +28,25 @@ import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.util.Log; import com.android.internal.R; -import com.android.server.credentials.metrics.CandidateBrowsingPhaseMetric; -import com.android.server.credentials.metrics.CandidatePhaseMetric; -import com.android.server.credentials.metrics.ChosenProviderFinalPhaseMetric; -import com.android.server.credentials.metrics.EntryEnum; -import com.android.server.credentials.metrics.InitialPhaseMetric; +import com.android.server.credentials.metrics.ApiName; +import com.android.server.credentials.metrics.ApiStatus; import com.android.server.credentials.metrics.ProviderStatusForMetrics; +import com.android.server.credentials.metrics.RequestSessionMetric; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; /** * Base class of a request session, that listens to UI events. This class must be extended * every time a new response type is expected from the providers. */ -abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialManagerUiCallback { +abstract class RequestSession<T, U, V> implements CredentialManagerUi.CredentialManagerUiCallback { private static final String TAG = "RequestSession"; // TODO: Revise access levels of attributes @@ -77,16 +73,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan protected final CancellationSignal mCancellationSignal; protected final Map<String, ProviderSession> mProviders = new HashMap<>(); - protected final InitialPhaseMetric mInitialPhaseMetric = new InitialPhaseMetric(); - protected final ChosenProviderFinalPhaseMetric - mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric(); - - // TODO(b/271135048) - Group metrics used in a scope together, such as here in RequestSession - // TODO(b/271135048) - Replace this with a new atom per each browsing emit (V4) - @NonNull - protected List<CandidateBrowsingPhaseMetric> mCandidateBrowsingPhaseMetric = new ArrayList<>(); - // As emits occur in sequential order, increment this counter and utilize - protected int mSequenceCounter = 0; + protected final RequestSessionMetric mRequestSessionMetric = new RequestSessionMetric(); protected final String mHybridService; @NonNull @@ -122,17 +109,8 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan mUserId, this); mHybridService = context.getResources().getString( R.string.config_defaultCredentialManagerHybridService); - initialPhaseMetricSetup(timestampStarted); - } - - private void initialPhaseMetricSetup(long timestampStarted) { - try { - mInitialPhaseMetric.setCredentialServiceStartedTimeNanoseconds(timestampStarted); - mInitialPhaseMetric.setSessionId(mRequestId.hashCode()); - mInitialPhaseMetric.setCallerUid(mCallingUid); - } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); - } + mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId, + mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType)); } public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo, @@ -140,11 +118,10 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan protected abstract void launchUiWithProviderData(ArrayList<ProviderData> providerDataList); - // Sets up the initial metric collector for use across all request session impls - protected void setupInitialPhaseMetric(int metricCode, int requestClassType) { - this.mInitialPhaseMetric.setApiName(metricCode); - this.mInitialPhaseMetric.setCountRequestClassType(requestClassType); - } + protected abstract void invokeClientCallbackSuccess(V response) throws RemoteException; + + protected abstract void invokeClientCallbackError(String errorType, String errorMsg) throws + RemoteException; public void addProviderSession(ComponentName componentName, ProviderSession providerSession) { mProviders.put(componentName.flattenToString(), providerSession); @@ -170,26 +147,12 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan return; } Log.i(TAG, "Provider session found"); - logBrowsingPhasePerSelect(selection, providerSession); + mRequestSessionMetric.collectMetricPerBrowsingSelect(selection, + providerSession.mProviderSessionMetric.getCandidatePhasePerProviderMetric()); providerSession.onUiEntrySelected(selection.getEntryKey(), selection.getEntrySubkey(), selection.getPendingIntentProviderResponse()); } - private void logBrowsingPhasePerSelect(UserSelectionDialogResult selection, - ProviderSession providerSession) { - try { - CandidateBrowsingPhaseMetric browsingPhaseMetric = new CandidateBrowsingPhaseMetric(); - browsingPhaseMetric.setSessionId(this.mInitialPhaseMetric.getSessionId()); - browsingPhaseMetric.setEntryEnum( - EntryEnum.getMetricCodeFromString(selection.getEntryKey())); - browsingPhaseMetric.setProviderUid(providerSession.mCandidatePhasePerProviderMetric - .getCandidateUid()); - this.mCandidateBrowsingPhaseMetric.add(browsingPhaseMetric); - } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); - } - } - protected void finishSession(boolean propagateCancellation) { Log.i(TAG, "finishing session"); if (propagateCancellation) { @@ -208,14 +171,6 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan return false; } - protected void logApiCall(ChosenProviderFinalPhaseMetric finalPhaseMetric, - List<CandidateBrowsingPhaseMetric> browsingPhaseMetrics, int apiStatus) { - // TODO (b/270403549) - this browsing phase object is fine but also have a new emit - // For the returned types by authentication entries - i.e. a CandidatePhase During Browse - // Possibly think of adding in more atoms for other APIs as well. - logApiCalled(finalPhaseMetric, browsingPhaseMetrics, apiStatus, ++mSequenceCounter); - } - protected boolean isSessionCancelled() { return mCancellationSignal.isCanceled(); } @@ -239,7 +194,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan ArrayList<ProviderData> providerDataList = getProviderDataForUi(); if (!providerDataList.isEmpty()) { Log.i(TAG, "provider list not empty about to initiate ui"); - MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter); + mRequestSessionMetric.logCandidatePhaseMetrics(mProviders); launchUiWithProviderData(providerDataList); } } @@ -251,7 +206,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan ArrayList<ProviderData> providerDataList = new ArrayList<>(); if (isSessionCancelled()) { - MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter); + mRequestSessionMetric.logCandidatePhaseMetrics(mProviders); finishSession(/*propagateCancellation=*/true); return providerDataList; } @@ -267,54 +222,65 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan return providerDataList; } - protected void collectFinalPhaseMetricStatus(boolean hasException, - ProviderStatusForMetrics finalSuccess) { - mChosenProviderFinalPhaseMetric.setHasException(hasException); - mChosenProviderFinalPhaseMetric.setChosenProviderStatus( - finalSuccess.getMetricCode()); - } - /** - * Called by RequestSession's upon chosen metric determination. It's expected that most bits - * are transferred here. However, certain new information, such as the selected provider's final - * exception bit, the framework to ui and back latency, or the ui response bit are set at other - * locations. Other information, such browsing metrics, api_status, and the sequence id count - * are combined together during the final emit moment with the actual and official - * {@link com.android.internal.util.FrameworkStatsLog} metric generation. + * Allows subclasses to directly finalize the call and set closing metrics on response. * - * @param componentName the componentName to associate with a provider + * @param response the response associated with the API call that just completed */ - protected void setChosenMetric(ComponentName componentName) { + protected void respondToClientWithResponseAndFinish(V response) { + mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(/*has_exception=*/ false, + ProviderStatusForMetrics.FINAL_SUCCESS); + if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { + Log.i(TAG, "Request has already been completed. This is strange."); + return; + } + if (isSessionCancelled()) { + mRequestSessionMetric.logApiCalledAtFinish( + /*apiStatus=*/ ApiStatus.CLIENT_CANCELED.getMetricCode()); + finishSession(/*propagateCancellation=*/true); + return; + } try { - CandidatePhaseMetric metric = this.mProviders.get(componentName.flattenToString()) - .mCandidatePhasePerProviderMetric; - - mChosenProviderFinalPhaseMetric.setSessionId(metric.getSessionId()); - mChosenProviderFinalPhaseMetric.setChosenUid(metric.getCandidateUid()); - - mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds( - metric.getQueryLatencyMicroseconds()); + invokeClientCallbackSuccess(response); + mRequestSessionMetric.logApiCalledAtFinish( + /*apiStatus=*/ ApiStatus.SUCCESS.getMetricCode()); + } catch (RemoteException e) { + mRequestSessionMetric.collectFinalPhaseProviderMetricStatus( + /*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE); + Log.i(TAG, "Issue while responding to client with a response : " + e.getMessage()); + mRequestSessionMetric.logApiCalledAtFinish( + /*apiStatus=*/ ApiStatus.FAILURE.getMetricCode()); + } + finishSession(/*propagateCancellation=*/false); + } - mChosenProviderFinalPhaseMetric.setServiceBeganTimeNanoseconds( - metric.getServiceBeganTimeNanoseconds()); - mChosenProviderFinalPhaseMetric.setQueryStartTimeNanoseconds( - metric.getStartQueryTimeNanoseconds()); - mChosenProviderFinalPhaseMetric.setQueryEndTimeNanoseconds(metric - .getQueryFinishTimeNanoseconds()); + /** + * Allows subclasses to directly finalize the call and set closing metrics on error completion. + * + * @param errorType the type of error given back in the flow + * @param errorMsg the error message given back in the flow + */ + protected void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { + mRequestSessionMetric.collectFinalPhaseProviderMetricStatus( + /*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE); + if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { + Log.i(TAG, "Request has already been completed. This is strange."); + return; + } + if (isSessionCancelled()) { + mRequestSessionMetric.logApiCalledAtFinish( + /*apiStatus=*/ ApiStatus.CLIENT_CANCELED.getMetricCode()); + finishSession(/*propagateCancellation=*/true); + return; + } - mChosenProviderFinalPhaseMetric.setNumEntriesTotal(metric.getNumEntriesTotal()); - mChosenProviderFinalPhaseMetric.setCredentialEntryCount(metric - .getCredentialEntryCount()); - mChosenProviderFinalPhaseMetric.setCredentialEntryTypeCount( - metric.getCredentialEntryTypeCount()); - mChosenProviderFinalPhaseMetric.setActionEntryCount(metric.getActionEntryCount()); - mChosenProviderFinalPhaseMetric.setRemoteEntryCount(metric.getRemoteEntryCount()); - mChosenProviderFinalPhaseMetric.setAuthenticationEntryCount( - metric.getAuthenticationEntryCount()); - mChosenProviderFinalPhaseMetric.setAvailableEntries(metric.getAvailableEntries()); - mChosenProviderFinalPhaseMetric.setFinalFinishTimeNanoseconds(System.nanoTime()); - } catch (Exception e) { - Log.w(TAG, "Unexpected error during metric logging: " + e); + try { + invokeClientCallbackError(errorType, errorMsg); + } catch (RemoteException e) { + Log.i(TAG, "Issue while responding to client with error : " + e.getMessage()); } + boolean isUserCanceled = errorType.contains(MetricUtilities.USER_CANCELED_SUBSTRING); + mRequestSessionMetric.logFailureOrUserCancel(isUserCanceled); + finishSession(/*propagateCancellation=*/false); } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java index abd749c38985..f40e73ee64da 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java +++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java @@ -16,12 +16,22 @@ package com.android.server.credentials.metrics; +import static android.credentials.ui.RequestInfo.TYPE_CREATE; +import static android.credentials.ui.RequestInfo.TYPE_GET; +import static android.credentials.ui.RequestInfo.TYPE_UNDEFINED; + import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_CLEAR_CREDENTIAL; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_CREATE_CREDENTIAL; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_GET_CREDENTIAL; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_UNKNOWN; +import android.credentials.ui.RequestInfo; +import android.util.Log; + +import java.util.AbstractMap; +import java.util.Map; + public enum ApiName { UNKNOWN(CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_UNKNOWN), GET_CREDENTIAL(CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_GET_CREDENTIAL), @@ -31,12 +41,24 @@ public enum ApiName { CREDENTIAL_MANAGER_INITIAL_PHASE__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE ); + private static final String TAG = "ApiName"; + private final int mInnerMetricCode; + private static final Map<String, Integer> sRequestInfoToMetric = Map.ofEntries( + new AbstractMap.SimpleEntry<>(TYPE_CREATE, + CREATE_CREDENTIAL.mInnerMetricCode), + new AbstractMap.SimpleEntry<>(TYPE_GET, + GET_CREDENTIAL.mInnerMetricCode), + new AbstractMap.SimpleEntry<>(TYPE_UNDEFINED, + CLEAR_CREDENTIAL.mInnerMetricCode) + ); + ApiName(int innerMetricCode) { this.mInnerMetricCode = innerMetricCode; } + /** * Gives the West-world version of the metric name. * @@ -45,4 +67,20 @@ public enum ApiName { public int getMetricCode() { return this.mInnerMetricCode; } + + /** + * Given a string key type known to the framework, this returns the known metric code associated + * with that string. This is mainly used by {@link RequestSessionMetric} collection contexts. + * This relies on {@link RequestInfo} string keys. + * + * @param stringKey a string key type for a particular request info + * @return the metric code associated with this request info's api name counterpart + */ + public static int getMetricCodeFromRequestInfo(String stringKey) { + if (!sRequestInfoToMetric.containsKey(stringKey)) { + Log.w(TAG, "Attempted to use an unsupported string key request info"); + return UNKNOWN.mInnerMetricCode; + } + return sRequestInfoToMetric.get(stringKey); + } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java index 40532946a5a0..10d4f9c7590e 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java @@ -16,12 +16,14 @@ package com.android.server.credentials.metrics; +import android.util.IntArray; import android.util.Log; import com.android.server.credentials.MetricUtilities; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; /** * The central candidate provider metric object that mimics our defined metric setup. @@ -70,7 +72,7 @@ public class CandidatePhaseMetric { // The count of authentication entries from this provider, defaults to -1 private int mAuthenticationEntryCount = -1; // Gathered to pass on to chosen provider when required - private final List<Integer> mAvailableEntries = new ArrayList<>(); + private final IntArray mAvailableEntries = new IntArray(); public CandidatePhaseMetric() { } @@ -263,6 +265,6 @@ public class CandidatePhaseMetric { * this metric */ public List<Integer> getAvailableEntries() { - return new ArrayList<>(this.mAvailableEntries); // no alias copy + return Arrays.stream(mAvailableEntries.toArray()).boxed().collect(Collectors.toList()); } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java new file mode 100644 index 000000000000..76fd4786f9ee --- /dev/null +++ b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.credentials.metrics; + +import android.annotation.NonNull; +import android.service.credentials.BeginCreateCredentialResponse; +import android.service.credentials.BeginGetCredentialResponse; +import android.service.credentials.CredentialEntry; +import android.util.Log; + +import com.android.server.credentials.MetricUtilities; + +import java.util.stream.Collectors; + +/** + * Provides contextual metric collection for objects generated from + * {@link com.android.server.credentials.ProviderSession} flows to isolate metric + * collection from the core codebase. For any future additions to the ProviderSession subclass + * list, metric collection should be added to this file. + */ +public class ProviderSessionMetric { + + private static final String TAG = "ProviderSessionMetric"; + + // Specific candidate provider metric for the provider this session handles + @NonNull + protected final CandidatePhaseMetric mCandidatePhasePerProviderMetric = + new CandidatePhaseMetric(); + + public ProviderSessionMetric() {} + + /** + * Retrieve the candidate provider phase metric and the data it contains. + */ + public CandidatePhaseMetric getCandidatePhasePerProviderMetric() { + return mCandidatePhasePerProviderMetric; + } + + /** + * This collects for ProviderSessions, with respect to the candidate providers, whether + * an exception occurred in the candidate call. + * + * @param hasException indicates if the candidate provider associated with an exception + */ + public void collectCandidateExceptionStatus(boolean hasException) { + mCandidatePhasePerProviderMetric.setHasException(hasException); + } + + /** + * Used to collect metrics at the update stage when a candidate provider gives back an update. + * + * @param isFailureStatus indicates the candidate provider sent back a terminated response + * @param isCompletionStatus indicates the candidate provider sent back a completion response + * @param providerSessionUid the uid of the provider + */ + public void collectCandidateMetricUpdate(boolean isFailureStatus, + boolean isCompletionStatus, int providerSessionUid) { + try { + mCandidatePhasePerProviderMetric.setCandidateUid(providerSessionUid); + mCandidatePhasePerProviderMetric + .setQueryFinishTimeNanoseconds(System.nanoTime()); + if (isFailureStatus) { + mCandidatePhasePerProviderMetric.setQueryReturned(false); + mCandidatePhasePerProviderMetric.setProviderQueryStatus( + ProviderStatusForMetrics.QUERY_FAILURE + .getMetricCode()); + } else if (isCompletionStatus) { + mCandidatePhasePerProviderMetric.setQueryReturned(true); + mCandidatePhasePerProviderMetric.setProviderQueryStatus( + ProviderStatusForMetrics.QUERY_SUCCESS + .getMetricCode()); + } + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Starts the collection of a single provider metric in the candidate phase of the API flow. + * It's expected that this should be called at the start of the query phase so that session id + * and timestamps can be shared. They can be accessed granular-ly through the underlying + * objects, but for {@link com.android.server.credentials.ProviderSession} context metrics, + * it's recommended to use these context-specified methods. + * + * @param initMetric the pre candidate phase metric collection object of type + * {@link InitialPhaseMetric} used to transfer initial information + */ + public void collectCandidateMetricSetupViaInitialMetric(InitialPhaseMetric initMetric) { + try { + mCandidatePhasePerProviderMetric.setSessionId(initMetric.getSessionId()); + mCandidatePhasePerProviderMetric.setServiceBeganTimeNanoseconds( + initMetric.getCredentialServiceStartedTimeNanoseconds()); + mCandidatePhasePerProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Once candidate providers give back entries, this helps collect their info for metric + * purposes. + * + * @param response contains entries and data from the candidate provider responses + * @param <R> the response type associated with the API flow in progress + */ + public <R> void collectCandidateEntryMetrics(R response) { + try { + if (response instanceof BeginGetCredentialResponse) { + beginGetCredentialResponseCollectionCandidateEntryMetrics( + (BeginGetCredentialResponse) response); + } else if (response instanceof BeginCreateCredentialResponse) { + beginCreateCredentialResponseCollectionCandidateEntryMetrics( + (BeginCreateCredentialResponse) response); + } else { + Log.i(TAG, "Your response type is unsupported for metric logging"); + } + + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + private void beginCreateCredentialResponseCollectionCandidateEntryMetrics( + BeginCreateCredentialResponse response) { + var createEntries = response.getCreateEntries(); + int numRemoteEntry = MetricUtilities.ZERO; + if (response.getRemoteCreateEntry() != null) { + numRemoteEntry = MetricUtilities.UNIT; + mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY); + } + int numCreateEntries = + createEntries == null ? MetricUtilities.ZERO : createEntries.size(); + if (numCreateEntries > MetricUtilities.ZERO) { + createEntries.forEach(c -> + mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY)); + } + mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCreateEntries + numRemoteEntry); + mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry); + mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCreateEntries); + mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(MetricUtilities.UNIT); + } + + private void beginGetCredentialResponseCollectionCandidateEntryMetrics( + BeginGetCredentialResponse response) { + int numCredEntries = response.getCredentialEntries().size(); + int numActionEntries = response.getActions().size(); + int numAuthEntries = response.getAuthenticationActions().size(); + int numRemoteEntry = MetricUtilities.ZERO; + if (response.getRemoteCredentialEntry() != null) { + numRemoteEntry = MetricUtilities.UNIT; + mCandidatePhasePerProviderMetric.addEntry(EntryEnum.REMOTE_ENTRY); + } + response.getCredentialEntries().forEach(c -> + mCandidatePhasePerProviderMetric.addEntry(EntryEnum.CREDENTIAL_ENTRY)); + response.getActions().forEach(c -> + mCandidatePhasePerProviderMetric.addEntry(EntryEnum.ACTION_ENTRY)); + response.getAuthenticationActions().forEach(c -> + mCandidatePhasePerProviderMetric.addEntry(EntryEnum.AUTHENTICATION_ENTRY)); + mCandidatePhasePerProviderMetric.setNumEntriesTotal(numCredEntries + numAuthEntries + + numActionEntries + numRemoteEntry); + mCandidatePhasePerProviderMetric.setCredentialEntryCount(numCredEntries); + int numTypes = (response.getCredentialEntries().stream() + .map(CredentialEntry::getType).collect( + Collectors.toSet())).size(); // Dedupe type strings + mCandidatePhasePerProviderMetric.setCredentialEntryTypeCount(numTypes); + mCandidatePhasePerProviderMetric.setActionEntryCount(numActionEntries); + mCandidatePhasePerProviderMetric.setAuthenticationEntryCount(numAuthEntries); + mCandidatePhasePerProviderMetric.setRemoteEntryCount(numRemoteEntry); + } +} diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java new file mode 100644 index 000000000000..325b7e1731af --- /dev/null +++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.credentials.metrics; + +import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase; +import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPhase; + +import android.annotation.NonNull; +import android.credentials.ui.UserSelectionDialogResult; +import android.os.IBinder; +import android.util.Log; + +import com.android.server.credentials.ProviderSession; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Provides contextual metric collection for objects generated from classes such as + * {@link com.android.server.credentials.GetRequestSession}, + * {@link com.android.server.credentials.CreateRequestSession}, + * and {@link com.android.server.credentials.ClearRequestSession} flows to isolate metric + * collection from the core codebase. For any future additions to the RequestSession subclass + * list, metric collection should be added to this file. + */ +public class RequestSessionMetric { + private static final String TAG = "RequestSessionMetric"; + + // As emits occur in sequential order, increment this counter and utilize + protected int mSequenceCounter = 0; + + protected final InitialPhaseMetric mInitialPhaseMetric = new InitialPhaseMetric(); + protected final ChosenProviderFinalPhaseMetric + mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric(); + // TODO(b/271135048) - Replace this with a new atom per each browsing emit (V4) + @NonNull + protected List<CandidateBrowsingPhaseMetric> mCandidateBrowsingPhaseMetric = new ArrayList<>(); + + public RequestSessionMetric() { + } + + /** + * Increments the metric emit sequence counter and returns the current state value of the + * sequence. + * + * @return the current state value of the metric emit sequence. + */ + public int returnIncrementSequence() { + return ++mSequenceCounter; + } + + + /** + * @return the initial metrics associated with the request session + */ + public InitialPhaseMetric getInitialPhaseMetric() { + return mInitialPhaseMetric; + } + + /** + * Upon starting the service, this fills the initial phase metric properly. + * + * @param timestampStarted the timestamp the service begins at + * @param mRequestId the IBinder used to retrieve a unique id + * @param mCallingUid the calling process's uid + * @param metricCode typically pulled from {@link ApiName} + */ + public void collectInitialPhaseMetricInfo(long timestampStarted, IBinder mRequestId, + int mCallingUid, int metricCode) { + try { + mInitialPhaseMetric.setCredentialServiceStartedTimeNanoseconds(timestampStarted); + mInitialPhaseMetric.setSessionId(mRequestId.hashCode()); + mInitialPhaseMetric.setCallerUid(mCallingUid); + mInitialPhaseMetric.setApiName(metricCode); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Collects whether the UI returned for metric purposes. + * + * @param uiReturned indicates whether the ui returns or not + */ + public void collectUiReturnedFinalPhase(boolean uiReturned) { + try { + mChosenProviderFinalPhaseMetric.setUiReturned(uiReturned); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Sets the start time for the UI being called for metric purposes. + * + * @param uiCallStartTime the nanosecond time when the UI call began + */ + public void collectUiCallStartTime(long uiCallStartTime) { + try { + mChosenProviderFinalPhaseMetric.setUiCallStartTimeNanoseconds(uiCallStartTime); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * When the UI responds to the framework at the very final phase, this collects the timestamp + * and status of the return for metric purposes. + * + * @param uiReturned indicates whether the ui returns or not + * @param uiEndTimestamp the nanosecond time when the UI call ended + */ + public void collectUiResponseData(boolean uiReturned, long uiEndTimestamp) { + try { + mChosenProviderFinalPhaseMetric.setUiReturned(uiReturned); + mChosenProviderFinalPhaseMetric.setUiCallEndTimeNanoseconds(uiEndTimestamp); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Collects the final chosen provider status, with the status value coming from + * {@link ApiStatus}. + * + * @param status the final status of the chosen provider + */ + public void collectChosenProviderStatus(int status) { + try { + mChosenProviderFinalPhaseMetric.setChosenProviderStatus(status); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Collects request class type count in the RequestSession flow. + * + * @param requestClassTypeCount the number of class types in the request + */ + public void collectGetFlowInitialMetricInfo(int requestClassTypeCount) { + try { + mInitialPhaseMetric.setCountRequestClassType(requestClassTypeCount); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * During browsing, where multiple entries can be selected, this collects the browsing phase + * metric information. + * TODO(b/271135048) - modify asap to account for a new metric emit per browse response to + * framework. + * + * @param selection contains the selected entry key type + * @param selectedProviderPhaseMetric contains the utility information of the selected provider + */ + public void collectMetricPerBrowsingSelect(UserSelectionDialogResult selection, + CandidatePhaseMetric selectedProviderPhaseMetric) { + try { + CandidateBrowsingPhaseMetric browsingPhaseMetric = new CandidateBrowsingPhaseMetric(); + browsingPhaseMetric.setSessionId(mInitialPhaseMetric.getSessionId()); + browsingPhaseMetric.setEntryEnum( + EntryEnum.getMetricCodeFromString(selection.getEntryKey())); + browsingPhaseMetric.setProviderUid(selectedProviderPhaseMetric.getCandidateUid()); + mCandidateBrowsingPhaseMetric.add(browsingPhaseMetric); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Updates the final phase metric with the designated bit + * + * @param exceptionBitFinalPhase represents if the final phase provider had an exception + */ + private void setHasExceptionFinalPhase(boolean exceptionBitFinalPhase) { + try { + mChosenProviderFinalPhaseMetric.setHasException(exceptionBitFinalPhase); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Allows encapsulating the overall final phase metric status from the chosen and final + * provider. + * + * @param hasException represents if the final phase provider had an exception + * @param finalStatus represents the final status of the chosen provider + */ + public void collectFinalPhaseProviderMetricStatus(boolean hasException, + ProviderStatusForMetrics finalStatus) { + try { + mChosenProviderFinalPhaseMetric.setHasException(hasException); + mChosenProviderFinalPhaseMetric.setChosenProviderStatus( + finalStatus.getMetricCode()); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Called by RequestSessions upon chosen metric determination. It's expected that most bits + * are transferred here. However, certain new information, such as the selected provider's final + * exception bit, the framework to ui and back latency, or the ui response bit are set at other + * locations. Other information, such browsing metrics, api_status, and the sequence id count + * are combined during the final emit moment with the actual and official + * {@link com.android.internal.util.FrameworkStatsLog} metric generation. + * + * @param candidatePhaseMetric the componentName to associate with a provider + */ + public void collectChosenMetricViaCandidateTransfer(CandidatePhaseMetric candidatePhaseMetric) { + try { + mChosenProviderFinalPhaseMetric.setSessionId(candidatePhaseMetric.getSessionId()); + mChosenProviderFinalPhaseMetric.setChosenUid(candidatePhaseMetric.getCandidateUid()); + + mChosenProviderFinalPhaseMetric.setQueryPhaseLatencyMicroseconds( + candidatePhaseMetric.getQueryLatencyMicroseconds()); + + mChosenProviderFinalPhaseMetric.setServiceBeganTimeNanoseconds( + candidatePhaseMetric.getServiceBeganTimeNanoseconds()); + mChosenProviderFinalPhaseMetric.setQueryStartTimeNanoseconds( + candidatePhaseMetric.getStartQueryTimeNanoseconds()); + mChosenProviderFinalPhaseMetric.setQueryEndTimeNanoseconds(candidatePhaseMetric + .getQueryFinishTimeNanoseconds()); + + mChosenProviderFinalPhaseMetric.setNumEntriesTotal(candidatePhaseMetric + .getNumEntriesTotal()); + mChosenProviderFinalPhaseMetric.setCredentialEntryCount(candidatePhaseMetric + .getCredentialEntryCount()); + mChosenProviderFinalPhaseMetric.setCredentialEntryTypeCount( + candidatePhaseMetric.getCredentialEntryTypeCount()); + mChosenProviderFinalPhaseMetric.setActionEntryCount(candidatePhaseMetric + .getActionEntryCount()); + mChosenProviderFinalPhaseMetric.setRemoteEntryCount(candidatePhaseMetric + .getRemoteEntryCount()); + mChosenProviderFinalPhaseMetric.setAuthenticationEntryCount( + candidatePhaseMetric.getAuthenticationEntryCount()); + mChosenProviderFinalPhaseMetric.setAvailableEntries(candidatePhaseMetric + .getAvailableEntries()); + mChosenProviderFinalPhaseMetric.setFinalFinishTimeNanoseconds(System.nanoTime()); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * In the final phase, this helps log use cases that were either pure failures or user + * canceled. It's expected that {@link #collectFinalPhaseProviderMetricStatus(boolean, + * ProviderStatusForMetrics) collectFinalPhaseProviderMetricStatus} is called prior to this. + * Otherwise, the logging will miss required bits + * + * @param isUserCanceledError a boolean indicating if the error was due to user cancelling + */ + public void logFailureOrUserCancel(boolean isUserCanceledError) { + try { + if (isUserCanceledError) { + setHasExceptionFinalPhase(/* has_exception */ false); + logApiCalledAtFinish( + /* apiStatus */ ApiStatus.USER_CANCELED.getMetricCode()); + } else { + logApiCalledAtFinish( + /* apiStatus */ ApiStatus.FAILURE.getMetricCode()); + } + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Handles candidate phase metric emit in the RequestSession context, after the candidate phase + * completes. + * + * @param providers a map with known providers and their held metric objects + */ + public void logCandidatePhaseMetrics(Map<String, ProviderSession> providers) { + try { + logApiCalledCandidatePhase(providers, ++mSequenceCounter); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Handles the final logging for RequestSession context for the final phase. + * + * @param apiStatus the final status of the api being called + */ + public void logApiCalledAtFinish(int apiStatus) { + try { + // TODO (b/270403549) - this browsing phase object is fine but also have a new emit + // For the returned types by authentication entries - i.e. a CandidatePhase During + // Browse + // Possibly think of adding in more atoms for other APIs as well. + logApiCalledFinalPhase(mChosenProviderFinalPhaseMetric, mCandidateBrowsingPhaseMetric, + apiStatus, + ++mSequenceCounter); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2479646e4561..770e728ba935 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -10617,38 +10617,59 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * - SYSTEM_UID * - adb unless hasIncompatibleAccountsOrNonAdb is true. */ + @GuardedBy("getLockObject()") private void enforceCanSetProfileOwnerLocked( - CallerIdentity caller, @Nullable ComponentName owner, int userHandle, + CallerIdentity caller, @Nullable ComponentName owner, @UserIdInt int userId, boolean hasIncompatibleAccountsOrNonAdb) { - UserInfo info = getUserInfo(userHandle); + UserInfo info = getUserInfo(userId); if (info == null) { // User doesn't exist. throw new IllegalArgumentException( - "Attempted to set profile owner for invalid userId: " + userHandle); + "Attempted to set profile owner for invalid userId: " + userId); } if (info.isGuest()) { throw new IllegalStateException("Cannot set a profile owner on a guest"); } - if (mOwners.hasProfileOwner(userHandle)) { - throw new IllegalStateException("Trying to set the profile owner, but profile owner " - + "is already set."); + if (mOwners.hasProfileOwner(userId)) { + StringBuilder errorMessage = new StringBuilder("Trying to set the profile owner"); + if (!hasIncompatibleAccountsOrNonAdb) { + append(errorMessage, owner).append(" on user ").append(userId); + } + errorMessage.append(", but profile owner"); + if (!hasIncompatibleAccountsOrNonAdb) { + appendProfileOwnerLocked(errorMessage, userId); + } + + throw new IllegalStateException(errorMessage.append(" is already set.").toString()); } - if (mOwners.hasDeviceOwner() && mOwners.getDeviceOwnerUserId() == userHandle) { - throw new IllegalStateException("Trying to set the profile owner, but the user " - + "already has a device owner."); + if (mOwners.hasDeviceOwner() && mOwners.getDeviceOwnerUserId() == userId) { + StringBuilder errorMessage = new StringBuilder("Trying to set the profile owner"); + if (!hasIncompatibleAccountsOrNonAdb) { + append(errorMessage, owner).append(" on user ").append(userId); + } + errorMessage.append(", but the user already has a device owner"); + if (!hasIncompatibleAccountsOrNonAdb) { + appendDeviceOwnerLocked(errorMessage); + } + throw new IllegalStateException(errorMessage.append('.').toString()); } if (isAdb(caller)) { - if ((mIsWatch || hasUserSetupCompleted(userHandle)) + if ((mIsWatch || hasUserSetupCompleted(userId)) && hasIncompatibleAccountsOrNonAdb) { - throw new IllegalStateException("Not allowed to set the profile owner because " - + "there are already some accounts on the profile"); + StringBuilder errorMessage = new StringBuilder("Not allowed to set the profile " + + "owner"); + if (!hasIncompatibleAccountsOrNonAdb) { + append(errorMessage, owner).append(" on user ").append(userId).append(' '); + } + throw new IllegalStateException(errorMessage.append(" because there are already " + + "some accounts on the profile.").toString()); } return; } Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); - if ((mIsWatch || hasUserSetupCompleted(userHandle))) { + if ((mIsWatch || hasUserSetupCompleted(userId))) { Preconditions.checkState(isSystemUid(caller), "Cannot set the profile owner on a user which is already set-up"); @@ -10665,31 +10686,62 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS * permission. */ + @GuardedBy("getLockObject()") private void enforceCanSetDeviceOwnerLocked( CallerIdentity caller, @Nullable ComponentName owner, @UserIdInt int deviceOwnerUserId, boolean hasIncompatibleAccountsOrNonAdb) { + boolean showComponentOnError = false; if (!isAdb(caller)) { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); + } else { + showComponentOnError = true; } final int code = checkDeviceOwnerProvisioningPreConditionLocked(owner, /* deviceOwnerUserId= */ deviceOwnerUserId, /* callingUserId*/ caller.getUserId(), isAdb(caller), hasIncompatibleAccountsOrNonAdb); if (code != STATUS_OK) { - throw new IllegalStateException( - computeProvisioningErrorString(code, deviceOwnerUserId)); + throw new IllegalStateException(computeProvisioningErrorStringLocked(code, + deviceOwnerUserId, owner, showComponentOnError)); } } - private static String computeProvisioningErrorString(int code, @UserIdInt int userId) { + private String computeProvisioningErrorString(int code, @UserIdInt int userId) { + synchronized (getLockObject()) { + return computeProvisioningErrorStringLocked(code, userId, /* newOwner= */ null, + /* showComponentOnError= */ false); + } + } + + @GuardedBy("getLockObject()") + private String computeProvisioningErrorStringLocked(int code, @UserIdInt int userId, + @Nullable ComponentName newOwner, boolean showComponentOnError) { switch (code) { case STATUS_OK: return "OK"; - case STATUS_HAS_DEVICE_OWNER: - return "Trying to set the device owner, but device owner is already set."; - case STATUS_USER_HAS_PROFILE_OWNER: - return "Trying to set the device owner, but the user already has a profile owner."; + case STATUS_HAS_DEVICE_OWNER: { + StringBuilder error = new StringBuilder("Trying to set the device owner"); + if (showComponentOnError && newOwner != null) { + append(error, newOwner); + } + error.append(", but device owner"); + if (showComponentOnError) { + appendDeviceOwnerLocked(error); + } + return error.append(" is already set.").toString(); + } + case STATUS_USER_HAS_PROFILE_OWNER: { + StringBuilder error = new StringBuilder("Trying to set the device owner"); + if (showComponentOnError && newOwner != null) { + append(error, newOwner); + } + error.append(", but the user already has a profile owner"); + if (showComponentOnError) { + appendProfileOwnerLocked(error, userId); + } + return error.append(".").toString(); + } case STATUS_USER_NOT_RUNNING: return "User " + userId + " not running."; case STATUS_NOT_SYSTEM_USER: @@ -10708,7 +10760,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { default: return "Unexpected @ProvisioningPreCondition: " + code; } + } + @GuardedBy("getLockObject()") + private void appendDeviceOwnerLocked(StringBuilder string) { + ComponentName deviceOwner = getDeviceOwnerComponent(/* callingUserOnly= */ false); + if (deviceOwner == null) { + // Shouldn't happen, but it doesn't hurt to check... + Slogf.wtf(LOG_TAG, "appendDeviceOwnerLocked(): device has no DO set"); + return; + } + append(string, deviceOwner); + } + + @GuardedBy("getLockObject()") + private void appendProfileOwnerLocked(StringBuilder string, @UserIdInt int userId) { + ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId); + if (profileOwner == null) { + // Shouldn't happen, but it doesn't hurt to check... + Slogf.wtf(LOG_TAG, "profileOwner(%d): PO not set", userId); + return; + } + append(string, profileOwner); + } + + private static StringBuilder append(StringBuilder string, ComponentName component) { + return string.append(" (").append(component.flattenToShortString()).append(')'); } private void enforceUserUnlocked(int userId) { @@ -19654,7 +19731,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setApplicationExemptions(String packageName, int[] exemptions) { + public void setApplicationExemptions(String callerPackage, String packageName, + int[] exemptions) { if (!mHasFeature) { return; } @@ -19665,7 +19743,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS)); - final CallerIdentity caller = getCallerIdentity(); + final CallerIdentity caller = getCallerIdentity(callerPackage); final ApplicationInfo packageInfo; packageInfo = getPackageInfoWithNullCheck(packageName, caller); @@ -22186,7 +22264,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES, MANAGE_DEVICE_POLICY_USERS, MANAGE_DEVICE_POLICY_SAFE_BOOT, - MANAGE_DEVICE_POLICY_TIME); + MANAGE_DEVICE_POLICY_TIME, + MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS); private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS = List.of( MANAGE_DEVICE_POLICY_ACROSS_USERS, @@ -22292,7 +22371,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { MANAGE_DEVICE_POLICY_PACKAGE_STATE, MANAGE_DEVICE_POLICY_RESET_PASSWORD, MANAGE_DEVICE_POLICY_STATUS_BAR, - MANAGE_DEVICE_POLICY_APP_RESTRICTIONS); + MANAGE_DEVICE_POLICY_APP_RESTRICTIONS, + MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS); private static final List<String> PROFILE_OWNER_PERMISSIONS = List.of( MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL, MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, @@ -22431,8 +22511,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCATION, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); - CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, - MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MICROPHONE, MANAGE_DEVICE_POLICY_ACROSS_USERS); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MOBILE_NETWORK, @@ -22587,6 +22665,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { hasPermissionOnTargetUser = hasPermission(CROSS_USER_PERMISSIONS.get(permission), callerPackageName); } + return hasPermissionOnOwnUser && hasPermissionOnTargetUser; } @@ -22627,7 +22706,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } // Check the permission for the role-holder if (isCallerDevicePolicyManagementRoleHolder(caller)) { - return anyDpcHasPermission(permission, mContext.getUserId()); + return anyDpcHasPermission(permission, caller.getUserId()); } if (DELEGATE_SCOPES.containsKey(permission)) { return isCallerDelegate(caller, DELEGATE_SCOPES.get(permission)); diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java index a1b9b98f95a4..2a256f262980 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java @@ -80,7 +80,7 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken); assertThat(state).isNotNull(); - assertThat(state.hasEdiorFocused()).isTrue(); + assertThat(state.hasEditorFocused()).isTrue(); assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED); assertThat(state.isRequestedImeVisible()).isTrue(); @@ -95,7 +95,7 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken); assertThat(state).isNotNull(); - assertThat(state.hasEdiorFocused()).isTrue(); + assertThat(state.hasEditorFocused()).isTrue(); assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED); assertThat(state.isRequestedImeVisible()).isTrue(); @@ -113,7 +113,7 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken); assertThat(state).isNotNull(); - assertThat(state.hasEdiorFocused()).isTrue(); + assertThat(state.hasEditorFocused()).isTrue(); assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED); assertThat(state.isRequestedImeVisible()).isFalse(); @@ -131,7 +131,7 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken); assertThat(state).isNotNull(); - assertThat(state.hasEdiorFocused()).isTrue(); + assertThat(state.hasEditorFocused()).isTrue(); assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED); assertThat(state.isRequestedImeVisible()).isFalse(); @@ -149,7 +149,7 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken); assertThat(state).isNotNull(); - assertThat(state.hasEdiorFocused()).isTrue(); + assertThat(state.hasEditorFocused()).isTrue(); assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED); assertThat(state.isRequestedImeVisible()).isFalse(); } diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SdCardEjectionTests.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SdCardEjectionTests.kt index 9f9e6a310d0b..d8139623f393 100644 --- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SdCardEjectionTests.kt +++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SdCardEjectionTests.kt @@ -57,7 +57,8 @@ class SdCardEjectionTests : BaseHostJUnit4Test() { @Parameterized.Parameters(name = "reboot={0}") @JvmStatic - fun parameters() = arrayOf(false, true) + // TODO(b/275403538): re-enable non-reboot scenarios with better tracking of APK removal + fun parameters() = arrayOf(/*false, */true) data class Volume( val diskId: String, @@ -200,15 +201,6 @@ class SdCardEjectionTests : BaseHostJUnit4Test() { // TODO: There must be a better way to prevent it from auto-mounting. removeVirtualDisk() device.reboot() - } else { - // Because PackageManager unmount scan is asynchronous, need to retry until the package - // has been unloaded. This only has to be done in the non-reboot case. Reboot will - // clear the data structure by its nature. - retryUntilSuccess { - // The compiler section will print the state of the physical APK - HostUtils.packageSection(device, pkgName, sectionName = "Compiler stats") - .any { it.contains("Unable to find package: $pkgName") } - } } } diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp index 1cc7ccc01283..5cc3371a1a6e 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp @@ -24,30 +24,45 @@ package { android_test_helper_app { name: "PackageManagerTestAppStub", manifest: "AndroidManifestVersion1.xml", - srcs: [] + srcs: [], } android_test_helper_app { name: "PackageManagerTestAppVersion1", - manifest: "AndroidManifestVersion1.xml" + manifest: "AndroidManifestVersion1.xml", + srcs: [ + "src/**/*.kt", + ], } android_test_helper_app { name: "PackageManagerTestAppVersion2", - manifest: "AndroidManifestVersion2.xml" + manifest: "AndroidManifestVersion2.xml", + srcs: [ + "src/**/*.kt", + ], } android_test_helper_app { name: "PackageManagerTestAppVersion3", - manifest: "AndroidManifestVersion3.xml" + manifest: "AndroidManifestVersion3.xml", + srcs: [ + "src/**/*.kt", + ], } android_test_helper_app { name: "PackageManagerTestAppVersion4", - manifest: "AndroidManifestVersion4.xml" + manifest: "AndroidManifestVersion4.xml", + srcs: [ + "src/**/*.kt", + ], } android_test_helper_app { name: "PackageManagerTestAppOriginalOverride", - manifest: "AndroidManifestOriginalOverride.xml" + manifest: "AndroidManifestOriginalOverride.xml", + srcs: [ + "src/**/*.kt", + ], } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java index d559b67218ca..8c8401497d48 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java @@ -70,6 +70,7 @@ import androidx.test.filters.LargeTest; import androidx.test.filters.SmallTest; import androidx.test.filters.Suppress; +import com.android.compatibility.common.util.CddTest; import com.android.internal.content.InstallLocationUtils; import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.pkg.parsing.ParsingPackageUtils; @@ -2911,6 +2912,7 @@ public class PackageManagerTests extends AndroidTestCase { } @LargeTest + @CddTest(requirements = {"3.1/C-0-8"}) public void testMinInstallableTargetSdkFail() throws Exception { // Test installing a package that doesn't meet the minimum installable sdk requirement setMinInstallableTargetSdkFeatureFlags(); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 390119c968cd..36d191b466ba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -1008,6 +1008,42 @@ public final class BroadcastQueueModernImplTest { dropboxEntryBroadcast2.first, expectedMergedBroadcast.first)); } + @Test + public void testDeliveryGroupPolicy_sameAction_differentMatchingCriteria() { + final Intent closeSystemDialogs1 = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + final BroadcastOptions optionsCloseSystemDialog1 = BroadcastOptions.makeBasic() + .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); + + final Intent closeSystemDialogs2 = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) + .putExtra("reason", "testing"); + final BroadcastOptions optionsCloseSystemDialog2 = BroadcastOptions.makeBasic() + .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) + .setDeliveryGroupMatchingKey(Intent.ACTION_CLOSE_SYSTEM_DIALOGS, "testing"); + + // Halt all processing so that we get a consistent view + mHandlerThread.getLooper().getQueue().postSyncBarrier(); + + mImpl.enqueueBroadcastLocked(makeBroadcastRecord( + closeSystemDialogs1, optionsCloseSystemDialog1)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord( + closeSystemDialogs2, optionsCloseSystemDialog2)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord( + closeSystemDialogs1, optionsCloseSystemDialog1)); + // Verify that only the older broadcast with no extras was removed. + final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN, + getUidForPackage(PACKAGE_GREEN)); + verifyPendingRecords(queue, List.of(closeSystemDialogs2, closeSystemDialogs1)); + + mImpl.enqueueBroadcastLocked(makeBroadcastRecord( + closeSystemDialogs2, optionsCloseSystemDialog2)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord( + closeSystemDialogs1, optionsCloseSystemDialog1)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord( + closeSystemDialogs2, optionsCloseSystemDialog2)); + // Verify that only the older broadcast with no extras was removed. + verifyPendingRecords(queue, List.of(closeSystemDialogs1, closeSystemDialogs2)); + } + private Pair<Intent, BroadcastOptions> createDropboxBroadcast(String tag, long timestampMs, int droppedCount) { final Intent dropboxEntryAdded = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED); diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java index 0ab984bd9381..fc503b7a749b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -66,7 +66,6 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.display.RampAnimator.DualRampAnimator; -import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.color.ColorDisplayService; import com.android.server.display.layout.Layout; import com.android.server.display.whitebalance.DisplayWhiteBalanceController; @@ -565,8 +564,8 @@ public final class DisplayPowerController2Test { .thenReturn(brightness); dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness()) + .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState @@ -603,8 +602,8 @@ public final class DisplayPowerController2Test { .thenReturn(brightness); dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness()) + .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 2d8fa1bcd8cd..2180a781e437 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -21,11 +21,13 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; @@ -50,6 +52,7 @@ import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.job.JobInfo; import android.content.ComponentName; import android.content.Context; @@ -81,6 +84,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; import java.time.Clock; import java.time.ZoneOffset; @@ -322,6 +326,109 @@ public class ConnectivityControllerTest { } @Test + public void testMeteredAllowed() throws Exception { + final JobInfo.Builder jobBuilder = createJob() + .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), + DataUnit.MEBIBYTES.toBytes(1)) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + final JobStatus job = spy(createJobStatus(jobBuilder)); + + final ConnectivityController controller = new ConnectivityController(mService, + mFlexibilityController); + + // Unmetered network is always "metered allowed" + { + final Network net = mock(Network.class); + final NetworkCapabilities caps = createCapabilitiesBuilder() + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .addCapability(NET_CAPABILITY_NOT_METERED) + .build(); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + } + + // Temporarily unmetered network is always "metered allowed" + { + final Network net = mock(Network.class); + final NetworkCapabilities caps = createCapabilitiesBuilder() + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) + .build(); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + } + + // Respond with the default values in NetworkPolicyManager. If those ever change enough + // to cause these tests to fail, we would likely need to go and update + // ConnectivityController. + doAnswer( + (Answer<Integer>) invocationOnMock + -> NetworkPolicyManager.getDefaultProcessNetworkCapabilities( + invocationOnMock.getArgument(0))) + .when(mService).getUidCapabilities(anyInt()); + + // Foreground is always allowed for metered network + { + final Network net = mock(Network.class); + final NetworkCapabilities caps = createCapabilitiesBuilder() + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .build(); + + when(mService.getUidProcState(anyInt())) + .thenReturn(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + + when(mService.getUidProcState(anyInt())) + .thenReturn(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + + when(mService.getUidProcState(anyInt())).thenReturn(ActivityManager.PROCESS_STATE_TOP); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + + when(mService.getUidProcState(anyInt())).thenReturn(JobInfo.BIAS_DEFAULT); + when(job.getFlags()).thenReturn(JobInfo.FLAG_WILL_BE_FOREGROUND); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + } + + when(mService.getUidProcState(anyInt())).thenReturn(ActivityManager.PROCESS_STATE_UNKNOWN); + when(job.getFlags()).thenReturn(0); + + // User initiated is always allowed for metered network + { + final Network net = mock(Network.class); + final NetworkCapabilities caps = createCapabilitiesBuilder() + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .build(); + when(job.shouldTreatAsUserInitiatedJob()).thenReturn(true); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + } + + // Background non-user-initiated should follow the app's restricted state + { + final Network net = mock(Network.class); + final NetworkCapabilities caps = createCapabilitiesBuilder() + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .build(); + when(job.shouldTreatAsUserInitiatedJob()).thenReturn(false); + when(mNetPolicyManager.getRestrictBackgroundStatus(anyInt())) + .thenReturn(ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + // Test cache + when(mNetPolicyManager.getRestrictBackgroundStatus(anyInt())) + .thenReturn(ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + // Clear cache + controller.onAppRemovedLocked(job.getSourcePackageName(), job.getSourceUid()); + assertFalse(controller.isSatisfied(job, net, caps, mConstants)); + // Test cache + when(mNetPolicyManager.getRestrictBackgroundStatus(anyInt())) + .thenReturn(ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED); + assertFalse(controller.isSatisfied(job, net, caps, mConstants)); + // Clear cache + controller.onAppRemovedLocked(job.getSourcePackageName(), job.getSourceUid()); + assertTrue(controller.isSatisfied(job, net, caps, mConstants)); + } + } + + @Test public void testStrongEnough_Cellular() { mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = 0; diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java index df6f9998c326..c040b1928ce4 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java @@ -397,6 +397,14 @@ public class JobStatusTest { job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, numSystemStops, 0, 0, 0); assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority()); + + // Less than 2 failures, but job is downgraded. + numFailures = 1; + numSystemStops = 0; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER); + assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority()); } @Test @@ -500,6 +508,80 @@ public class JobStatusTest { } @Test + public void testGetEffectivePriority_UserInitiated() { + final JobInfo jobInfo = + new JobInfo.Builder(101, new ComponentName("foo", "bar")) + .setUserInitiated(true) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .build(); + JobStatus job = createJobStatus(jobInfo); + + // Less than 2 failures, priority shouldn't be affected. + assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority()); + int numFailures = 1; + int numSystemStops = 0; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority()); + + // 2+ failures, priority shouldn't be affected while job is still a UI job + numFailures = 2; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority()); + numFailures = 5; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority()); + numFailures = 8; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority()); + + // System stops shouldn't factor in the downgrade. + numSystemStops = 10; + numFailures = 0; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority()); + + // Job can no long run as user-initiated. Downgrades should be effective. + // Priority can't be max. + job = createJobStatus(jobInfo); + job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER); + assertFalse(job.shouldTreatAsUserInitiatedJob()); + + // Less than 2 failures. + assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority()); + numFailures = 1; + numSystemStops = 0; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority()); + + // 2+ failures, priority should start getting lower + numFailures = 2; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority()); + numFailures = 5; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority()); + numFailures = 8; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority()); + + // System stops shouldn't factor in the downgrade. + numSystemStops = 10; + numFailures = 0; + job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures, + numSystemStops, 0, 0, 0); + assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority()); + } + + @Test public void testShouldTreatAsUserInitiated() { JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar")) .setUserInitiated(false) diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java index 4d112965b932..a1937cec706c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java @@ -53,6 +53,7 @@ import com.google.common.util.concurrent.MoreExecutors; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -69,6 +70,7 @@ public class LocationManagerServiceTest { private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID; private static final String CALLER_PACKAGE = "caller_package"; private static final String MISSING_PERMISSION = "missing_permission"; + private static final String ATTRIBUTION_TAG = "test_tag"; private TestInjector mInjector; private LocationManagerService mLocationManagerService; @@ -136,6 +138,7 @@ public class LocationManagerServiceTest { } @Test + @Ignore("b/274432939") // Test is flaky for as of yet unknown reasons public void testRequestLocationUpdates() { LocationRequest request = new LocationRequest.Builder(0).build(); mLocationManagerService.registerLocationListener( @@ -143,7 +146,7 @@ public class LocationManagerServiceTest { request, mLocationListener, CALLER_PACKAGE, - /* attributionTag= */ null, + ATTRIBUTION_TAG, "any_listener_id"); verify(mProviderWithPermission).onSetRequestPublic(any()); } @@ -159,7 +162,7 @@ public class LocationManagerServiceTest { request, mLocationListener, CALLER_PACKAGE, - /* attributionTag= */ null, + ATTRIBUTION_TAG, "any_listener_id")); } diff --git a/services/tests/servicestests/res/xml/keyboard_layouts.xml b/services/tests/servicestests/res/xml/keyboard_layouts.xml index b5a05fcaff17..5f3fcd6eaed0 100644 --- a/services/tests/servicestests/res/xml/keyboard_layouts.xml +++ b/services/tests/servicestests/res/xml/keyboard_layouts.xml @@ -73,9 +73,17 @@ android:keyboardLocale="ru-Cyrl" /> <keyboard-layout + android:name="keyboard_layout_english_without_script_code" + android:label="English(No script code)" + android:keyboardLayout="@raw/dummy_keyboard_layout" + android:keyboardLocale="en" + android:keyboardLayoutType="qwerty" /> + + <keyboard-layout android:name="keyboard_layout_vendorId:1,productId:1" android:label="vendorId:1,productId:1" android:keyboardLayout="@raw/dummy_keyboard_layout" androidprv:vendorId="1" androidprv:productId="1" /> + </keyboard-layouts> diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index 8994a488bd56..ab8f3f2279fe 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -383,6 +383,7 @@ public class UserControllerTest { // Call dispatchUserSwitch and verify that observer was called only once mInjector.mHandler.clearAllRecordedMessages(); mUserController.dispatchUserSwitch(userState, oldUserId, newUserId); + verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID)); verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any()); Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG); Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes(); @@ -413,6 +414,7 @@ public class UserControllerTest { // Call dispatchUserSwitch and verify that observer was called only once mInjector.mHandler.clearAllRecordedMessages(); mUserController.dispatchUserSwitch(userState, oldUserId, newUserId); + verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID)); verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any()); // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout) Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes(); diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java index 169210f627b8..ab2749e14094 100644 --- a/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java +++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java @@ -33,6 +33,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -52,10 +53,12 @@ public class CredentialDescriptionRegistryTest { private static final String CALLING_PACKAGE_NAME_2 = "com.credman.app2"; private static final String MDOC_CREDENTIAL_TYPE = "MDOC"; private static final String PASSKEY_CREDENTIAL_TYPE = "PASSKEY"; - private static final String FLATTENED_REGISTRY = - "FLATTENED_REQ;FLATTENED_REQ123;FLATTENED_REQa"; - private static final String FLATTENED_REGISTRY_2 = "FLATTENED_REQ_2"; - private static final String FLATTENED_REQUEST = "FLATTENED_REQ;FLATTENED_REQ123"; + private static final HashSet<String> FLATTENED_REGISTRY = new HashSet<>(List.of( + "FLATTENED_REQ", "FLATTENED_REQ123", "FLATTENED_REQa")); + private static final HashSet<String> FLATTENED_REGISTRY_2 = + new HashSet<>(List.of("FLATTENED_REQ_2")); + private static final HashSet<String> FLATTENED_REQUEST = + new HashSet<>(List.of("FLATTENED_REQ;FLATTENED_REQ123")); private CredentialDescriptionRegistry mCredentialDescriptionRegistry; private CredentialEntry mEntry; diff --git a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java index 4c8e70ae5109..6bc0fbf3101c 100644 --- a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java @@ -18,6 +18,7 @@ package com.android.server.credentials; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -59,6 +60,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.security.cert.CertificateException; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -74,7 +76,8 @@ public class ProviderRegistryGetSessionTest { private static final String CALLING_PACKAGE_NAME = "com.credman.app"; private static final int USER_ID_1 = 1; - private static final String FLATTENED_REQUEST = "FLATTENED_REQ"; + private static final ArrayList<String> FLATTENED_REQUEST = + new ArrayList<>(List.of("FLATTENED_REQ")); private static final String CP_SERVICE_NAME = "CredentialProvider"; private static final ComponentName CREDENTIAL_PROVIDER_COMPONENT = new ComponentName(CALLING_PACKAGE_NAME, CP_SERVICE_NAME); @@ -102,7 +105,8 @@ public class ProviderRegistryGetSessionTest { MockitoAnnotations.initMocks(this); final Context context = ApplicationProvider.getApplicationContext(); mRetrievalData = new Bundle(); - mRetrievalData.putString(CredentialOption.FLATTENED_REQUEST, FLATTENED_REQUEST); + mRetrievalData.putStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS, + FLATTENED_REQUEST); mCallingAppInfo = createCallingAppInfo(); mGetCredentialOption = new CredentialOption(CREDENTIAL_TYPE, mRetrievalData, new Bundle(), false); @@ -114,10 +118,10 @@ public class ProviderRegistryGetSessionTest { when(mEntry.getSlice()).thenReturn(mSlice); when(mEntry2.getSlice()).thenReturn(mSlice2); mResult = new CredentialDescriptionRegistry.FilterResult(CALLING_PACKAGE_NAME, - FLATTENED_REQUEST, + new HashSet<>(FLATTENED_REQUEST), List.of(mEntry, mEntry2)); mResponse.add(mResult); - when(mCredentialDescriptionRegistry.getFilteredResultForProvider(anyString(), anyString())) + when(mCredentialDescriptionRegistry.getFilteredResultForProvider(anyString(), anySet())) .thenReturn(mResponse); mProviderRegistryGetSession = ProviderRegistryGetSession .createNewSession(context, USER_ID_1, mGetRequestSession, @@ -129,7 +133,8 @@ public class ProviderRegistryGetSessionTest { @Test public void testInvokeSession_existingProvider_setsResults() { final ArgumentCaptor<String> packageNameCaptor = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor<String> flattenedRequestCaptor = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor<Set<String>> flattenedRequestCaptor = + ArgumentCaptor.forClass(Set.class); final ArgumentCaptor<ProviderSession.Status> statusCaptor = ArgumentCaptor.forClass(ProviderSession.Status.class); final ArgumentCaptor<ComponentName> cpComponentNameCaptor = @@ -141,9 +146,9 @@ public class ProviderRegistryGetSessionTest { packageNameCaptor.capture(), flattenedRequestCaptor.capture()); assertThat(packageNameCaptor.getValue()).isEqualTo(CALLING_PACKAGE_NAME); - assertThat(flattenedRequestCaptor.getValue()).isEqualTo(FLATTENED_REQUEST); + assertThat(flattenedRequestCaptor.getValue()).containsExactly(FLATTENED_REQUEST); verify(mGetRequestSession).onProviderStatusChanged(statusCaptor.capture(), - cpComponentNameCaptor.capture()); + cpComponentNameCaptor.capture(), ProviderSession.CredentialsSource.REGISTRY); assertThat(statusCaptor.getValue()).isEqualTo(ProviderSession.Status.CREDENTIALS_RECEIVED); assertThat(cpComponentNameCaptor.getValue()).isEqualTo(CREDENTIAL_PROVIDER_COMPONENT); assertThat(mProviderRegistryGetSession.mCredentialEntries).hasSize(2); @@ -240,8 +245,6 @@ public class ProviderRegistryGetSessionTest { ProviderRegistryGetSession.CREDENTIAL_ENTRY_KEY, entryKey, providerPendingIntentResponse); - verify(mGetRequestSession).onProviderStatusChanged(statusCaptor.capture(), - cpComponentNameCaptor.capture()); assertThat(statusCaptor.getValue()).isEqualTo(ProviderSession.Status.CREDENTIALS_RECEIVED); verify(mGetRequestSession).onFinalErrorReceived(cpComponentNameCaptor.capture(), exceptionTypeCaptor.capture(), exceptionMessageCaptor.capture()); @@ -274,8 +277,6 @@ public class ProviderRegistryGetSessionTest { ProviderRegistryGetSession.CREDENTIAL_ENTRY_KEY, entryKey, providerPendingIntentResponse); - verify(mGetRequestSession).onProviderStatusChanged(statusCaptor.capture(), - cpComponentNameCaptor.capture()); assertThat(statusCaptor.getValue()).isEqualTo(ProviderSession.Status.CREDENTIALS_RECEIVED); verify(mGetRequestSession).onFinalErrorReceived(cpComponentNameCaptor.capture(), exceptionTypeCaptor.capture(), exceptionMessageCaptor.capture()); @@ -308,8 +309,6 @@ public class ProviderRegistryGetSessionTest { ProviderRegistryGetSession.CREDENTIAL_ENTRY_KEY, entryKey, providerPendingIntentResponse); - verify(mGetRequestSession).onProviderStatusChanged(statusCaptor.capture(), - cpComponentNameCaptor.capture()); assertThat(statusCaptor.getValue()).isEqualTo(ProviderSession.Status.CREDENTIALS_RECEIVED); verify(mGetRequestSession).onFinalResponseReceived(cpComponentNameCaptor.capture(), getCredentialResponseCaptor.capture()); diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java new file mode 100644 index 000000000000..eb208d2e6c7f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.display.brightness.strategy; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.ContextWrapper; +import android.hardware.display.BrightnessConfiguration; +import android.hardware.display.DisplayManagerInternal; +import android.os.PowerManager; +import android.os.UserHandle; +import android.provider.Settings; +import android.test.mock.MockContentResolver; +import android.view.Display; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.test.FakeSettingsProvider; +import com.android.internal.util.test.FakeSettingsProviderRule; +import com.android.server.display.AutomaticBrightnessController; +import com.android.server.display.brightness.BrightnessReason; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class AutomaticBrightnessStrategyTest { + private static final int DISPLAY_ID = 0; + @Rule + public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); + + @Mock + private AutomaticBrightnessController mAutomaticBrightnessController; + + private BrightnessConfiguration mBrightnessConfiguration; + private float mDefaultScreenAutoBrightnessAdjustment; + private Context mContext; + private AutomaticBrightnessStrategy mAutomaticBrightnessStrategy; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); + final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext); + when(mContext.getContentResolver()).thenReturn(resolver); + mDefaultScreenAutoBrightnessAdjustment = Settings.System.getFloat( + mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, Float.NaN); + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.5f); + mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, DISPLAY_ID); + + mBrightnessConfiguration = new BrightnessConfiguration.Builder( + new float[]{0f, 1f}, new float[]{0, PowerManager.BRIGHTNESS_ON}).build(); + when(mAutomaticBrightnessController.hasUserDataPoints()).thenReturn(true); + mAutomaticBrightnessStrategy.setAutomaticBrightnessController( + mAutomaticBrightnessController); + mAutomaticBrightnessStrategy.setBrightnessConfiguration(mBrightnessConfiguration, + true); + } + + @After + public void after() { + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, mDefaultScreenAutoBrightnessAdjustment); + } + + @Test + public void setAutoBrightnessWhenDisabled() { + mAutomaticBrightnessStrategy.setUseAutoBrightness(false); + int targetDisplayState = Display.STATE_ON; + boolean allowAutoBrightnessWhileDozing = false; + float brightnessState = Float.NaN; + int brightnessReason = BrightnessReason.REASON_OVERRIDE; + int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; + float lastUserSetBrightness = 0.2f; + boolean userSetBrightnessChanged = true; + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(true); + mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState, + allowAutoBrightnessWhileDozing, brightnessState, brightnessReason, policy, + lastUserSetBrightness, userSetBrightnessChanged); + verify(mAutomaticBrightnessController) + .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, + mBrightnessConfiguration, + lastUserSetBrightness, + userSetBrightnessChanged, 0.5f, + false, policy, true); + } + + @Test + public void setAutoBrightnessWhenEnabledAndDisplayIsDozing() { + mAutomaticBrightnessStrategy.setUseAutoBrightness(true); + int targetDisplayState = Display.STATE_DOZE; + float brightnessState = Float.NaN; + boolean allowAutoBrightnessWhileDozing = true; + int brightnessReason = BrightnessReason.REASON_DOZE; + int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; + float lastUserSetBrightness = 0.2f; + boolean userSetBrightnessChanged = true; + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.4f); + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(false); + mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState, + allowAutoBrightnessWhileDozing, brightnessState, brightnessReason, policy, + lastUserSetBrightness, userSetBrightnessChanged); + verify(mAutomaticBrightnessController) + .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, + mBrightnessConfiguration, + lastUserSetBrightness, + userSetBrightnessChanged, 0.4f, + true, policy, true); + } + + @Test + public void setAutoBrightnessWhenEnabledAndDisplayIsOn() { + mAutomaticBrightnessStrategy.setUseAutoBrightness(true); + int targetDisplayState = Display.STATE_ON; + float brightnessState = Float.NaN; + boolean allowAutoBrightnessWhileDozing = false; + int brightnessReason = BrightnessReason.REASON_OVERRIDE; + float lastUserSetBrightness = 0.2f; + boolean userSetBrightnessChanged = true; + int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; + float pendingBrightnessAdjustment = 0.1f; + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingBrightnessAdjustment); + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(false); + mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState, + allowAutoBrightnessWhileDozing, brightnessState, brightnessReason, policy, + lastUserSetBrightness, userSetBrightnessChanged); + verify(mAutomaticBrightnessController) + .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, + mBrightnessConfiguration, + lastUserSetBrightness, + userSetBrightnessChanged, pendingBrightnessAdjustment, + true, policy, true); + } + + @Test + public void accommodateUserBrightnessChangesWorksAsExpected() { + // Verify the state if automaticBrightnessController is configured. + assertFalse(mAutomaticBrightnessStrategy.isShortTermModelActive()); + boolean userSetBrightnessChanged = true; + float lastUserSetScreenBrightness = 0.2f; + int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; + BrightnessConfiguration brightnessConfiguration = new BrightnessConfiguration.Builder( + new float[]{0f, 1f}, new float[]{0, PowerManager.BRIGHTNESS_ON}).build(); + int autoBrightnessState = AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED; + float temporaryAutoBrightnessAdjustments = 0.4f; + mAutomaticBrightnessStrategy.setShouldResetShortTermModel(true); + setTemporaryAutoBrightnessAdjustment(temporaryAutoBrightnessAdjustments); + mAutomaticBrightnessStrategy.accommodateUserBrightnessChanges(userSetBrightnessChanged, + lastUserSetScreenBrightness, policy, brightnessConfiguration, + autoBrightnessState); + verify(mAutomaticBrightnessController).configure(autoBrightnessState, + brightnessConfiguration, + lastUserSetScreenBrightness, + userSetBrightnessChanged, temporaryAutoBrightnessAdjustments, + /* userChangedAutoBrightnessAdjustment= */ false, policy, + /* shouldResetShortTermModel= */ true); + assertTrue(mAutomaticBrightnessStrategy.isTemporaryAutoBrightnessAdjustmentApplied()); + assertFalse(mAutomaticBrightnessStrategy.shouldResetShortTermModel()); + assertTrue(mAutomaticBrightnessStrategy.isShortTermModelActive()); + // Verify the state when automaticBrightnessController is not configured + setTemporaryAutoBrightnessAdjustment(Float.NaN); + mAutomaticBrightnessStrategy.setAutomaticBrightnessController(null); + mAutomaticBrightnessStrategy.setShouldResetShortTermModel(true); + mAutomaticBrightnessStrategy.accommodateUserBrightnessChanges(userSetBrightnessChanged, + lastUserSetScreenBrightness, policy, brightnessConfiguration, + autoBrightnessState); + assertFalse(mAutomaticBrightnessStrategy.isTemporaryAutoBrightnessAdjustmentApplied()); + assertTrue(mAutomaticBrightnessStrategy.shouldResetShortTermModel()); + assertFalse(mAutomaticBrightnessStrategy.isShortTermModelActive()); + } + + @Test + public void adjustAutomaticBrightnessStateIfValid() throws Settings.SettingNotFoundException { + float brightnessState = 0.3f; + float autoBrightnessAdjustment = 0.2f; + when(mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()).thenReturn( + autoBrightnessAdjustment); + mAutomaticBrightnessStrategy.adjustAutomaticBrightnessStateIfValid(brightnessState); + assertTrue(mAutomaticBrightnessStrategy.hasAppliedAutoBrightness()); + assertEquals(autoBrightnessAdjustment, + mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f); + assertEquals(autoBrightnessAdjustment, Settings.System.getFloatForUser( + mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, + UserHandle.USER_CURRENT), 0.0f); + assertEquals(BrightnessReason.ADJUSTMENT_AUTO, + mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags()); + float invalidBrightness = -0.5f; + mAutomaticBrightnessStrategy + .adjustAutomaticBrightnessStateIfValid(invalidBrightness); + assertFalse(mAutomaticBrightnessStrategy.hasAppliedAutoBrightness()); + assertEquals(autoBrightnessAdjustment, + mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f); + assertEquals(0, + mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags()); + } + + @Test + public void updatePendingAutoBrightnessAdjustments() { + // Verify the state when the pendingAutoBrightnessAdjustments are not present + setPendingAutoBrightnessAdjustment(Float.NaN); + assertFalse(mAutomaticBrightnessStrategy.processPendingAutoBrightnessAdjustments()); + assertFalse(mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged()); + // Verify the state when the pendingAutoBrightnessAdjustments are present, but + // pendingAutoBrightnessAdjustments and autoBrightnessAdjustments are the same + float autoBrightnessAdjustment = 0.3f; + setPendingAutoBrightnessAdjustment(autoBrightnessAdjustment); + setAutoBrightnessAdjustment(autoBrightnessAdjustment); + assertFalse(mAutomaticBrightnessStrategy.processPendingAutoBrightnessAdjustments()); + assertFalse(mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged()); + assertEquals(Float.NaN, mAutomaticBrightnessStrategy.getPendingAutoBrightnessAdjustment(), + 0.0f); + // Verify the state when the pendingAutoBrightnessAdjustments are present, and + // pendingAutoBrightnessAdjustments and autoBrightnessAdjustments are not the same + float pendingAutoBrightnessAdjustment = 0.2f; + setPendingAutoBrightnessAdjustment(pendingAutoBrightnessAdjustment); + setTemporaryAutoBrightnessAdjustment(0.1f); + assertTrue(mAutomaticBrightnessStrategy.processPendingAutoBrightnessAdjustments()); + assertTrue(mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged()); + assertEquals(pendingAutoBrightnessAdjustment, + mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f); + assertEquals(Float.NaN, mAutomaticBrightnessStrategy.getPendingAutoBrightnessAdjustment(), + 0.0f); + assertEquals(Float.NaN, mAutomaticBrightnessStrategy.getTemporaryAutoBrightnessAdjustment(), + 0.0f); + } + + @Test + public void setAutomaticBrightnessWorksAsExpected() { + float automaticScreenBrightness = 0.3f; + AutomaticBrightnessController automaticBrightnessController = mock( + AutomaticBrightnessController.class); + when(automaticBrightnessController.getAutomaticScreenBrightness()).thenReturn( + automaticScreenBrightness); + mAutomaticBrightnessStrategy.setAutomaticBrightnessController( + automaticBrightnessController); + assertEquals(automaticScreenBrightness, + mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(), 0.0f); + } + + @Test + public void shouldUseAutoBrightness() { + mAutomaticBrightnessStrategy.setUseAutoBrightness(true); + assertTrue(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()); + } + + @Test + public void setPendingAutoBrightnessAdjustments() throws Settings.SettingNotFoundException { + float pendingAutoBrightnessAdjustments = 0.3f; + setPendingAutoBrightnessAdjustment(pendingAutoBrightnessAdjustments); + assertEquals(pendingAutoBrightnessAdjustments, + mAutomaticBrightnessStrategy.getPendingAutoBrightnessAdjustment(), 0.0f); + assertEquals(pendingAutoBrightnessAdjustments, Settings.System.getFloatForUser( + mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, + UserHandle.USER_CURRENT), 0.0f); + } + + @Test + public void setTemporaryAutoBrightnessAdjustment() { + float temporaryAutoBrightnessAdjustment = 0.3f; + mAutomaticBrightnessStrategy.setTemporaryAutoBrightnessAdjustment( + temporaryAutoBrightnessAdjustment); + assertEquals(temporaryAutoBrightnessAdjustment, + mAutomaticBrightnessStrategy.getTemporaryAutoBrightnessAdjustment(), 0.0f); + } + + @Test + public void setAutoBrightnessApplied() { + mAutomaticBrightnessStrategy.setAutoBrightnessApplied(true); + assertTrue(mAutomaticBrightnessStrategy.hasAppliedAutoBrightness()); + } + + @Test + public void testVerifyNoAutoBrightnessAdjustmentsArePopulatedForNonDefaultDisplay() { + int newDisplayId = 1; + mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, newDisplayId); + mAutomaticBrightnessStrategy.putAutoBrightnessAdjustmentSetting(0.3f); + assertEquals(0.5f, mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), + 0.0f); + } + + private void setPendingAutoBrightnessAdjustment(float pendingAutoBrightnessAdjustment) { + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingAutoBrightnessAdjustment); + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(false); + } + + private void setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment) { + mAutomaticBrightnessStrategy.setTemporaryAutoBrightnessAdjustment( + temporaryAutoBrightnessAdjustment); + } + + private void setAutoBrightnessAdjustment(float autoBrightnessAdjustment) { + mAutomaticBrightnessStrategy.putAutoBrightnessAdjustmentSetting(autoBrightnessAdjustment); + } +} diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt index 1d23e12d0a10..00eb80d21f47 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt @@ -24,6 +24,7 @@ import android.hardware.input.IKeyboardBacklightListener import android.hardware.input.IKeyboardBacklightState import android.hardware.input.InputManager import android.hardware.lights.Light +import android.os.UEventObserver import android.os.test.TestLooper import android.platform.test.annotations.Presubmit import android.view.InputDevice @@ -39,6 +40,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.Mock +import org.mockito.Mockito.any import org.mockito.Mockito.anyInt import org.mockito.Mockito.eq import org.mockito.Mockito.spy @@ -95,6 +97,7 @@ class KeyboardBacklightControllerTests { private lateinit var testLooper: TestLooper private var lightColorMap: HashMap<Int, Int> = HashMap() private var lastBacklightState: KeyboardBacklightState? = null + private var sysfsNodeChanges = 0 @Before fun setup() { @@ -121,6 +124,9 @@ class KeyboardBacklightControllerTests { lightColorMap.put(args[1] as Int, args[2] as Int) } lightColorMap.clear() + `when`(native.sysfsNodeChanged(any())).then { + sysfsNodeChanges++ + } } @After @@ -393,6 +399,64 @@ class KeyboardBacklightControllerTests { ) } + @Test + fun testKeyboardBacklightSysfsNodeAdded_AfterInputDeviceAdded() { + var counter = sysfsNodeChanges + keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent( + "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc::no_backlight\u0000" + )) + assertEquals( + "Should not reload sysfs node if UEvent path doesn't contain kbd_backlight", + counter, + sysfsNodeChanges + ) + + keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent( + "ACTION=add\u0000SUBSYSTEM=power\u0000DEVPATH=/xyz/leds/abc::kbd_backlight\u0000" + )) + assertEquals( + "Should not reload sysfs node if UEvent doesn't belong to subsystem LED", + counter, + sysfsNodeChanges + ) + + keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent( + "ACTION=remove\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc::kbd_backlight\u0000" + )) + assertEquals( + "Should not reload sysfs node if UEvent doesn't have ACTION(add)", + counter, + sysfsNodeChanges + ) + + keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent( + "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/pqr/abc::kbd_backlight\u0000" + )) + assertEquals( + "Should not reload sysfs node if UEvent path doesn't belong to leds/ directory", + counter, + sysfsNodeChanges + ) + + keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent( + "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc::kbd_backlight\u0000" + )) + assertEquals( + "Should reload sysfs node if a valid Keyboard backlight LED UEvent occurs", + ++counter, + sysfsNodeChanges + ) + + keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent( + "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc:kbd_backlight:red\u0000" + )) + assertEquals( + "Should reload sysfs node if a valid Keyboard backlight LED UEvent occurs", + ++counter, + sysfsNodeChanges + ) + } + inner class KeyboardBacklightListener : IKeyboardBacklightListener.Stub() { override fun onBrightnessChanged( deviceId: Int, diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt index b660926f1394..7729fa29667b 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt @@ -26,7 +26,6 @@ import android.content.pm.ServiceInfo import android.hardware.input.IInputManager import android.hardware.input.InputManager import android.hardware.input.KeyboardLayout -import android.icu.lang.UScript import android.icu.util.ULocale import android.os.Bundle import android.os.test.TestLooper @@ -52,7 +51,6 @@ import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.IOException import java.io.InputStream -import java.util.Locale private fun createKeyboard( deviceId: Int, @@ -553,24 +551,17 @@ class KeyboardLayoutManagerTests { 0, keyboardLayouts.size ) - - val englishScripts = UScript.getCode(Locale.forLanguageTag("hi-Latn")) - for (kl in keyboardLayouts) { - var isCompatible = false - for (i in 0 until kl.locales.size()) { - val locale: Locale = kl.locales.get(i) ?: continue - val scripts = UScript.getCode(locale) - if (scripts != null && areScriptsCompatible(scripts, englishScripts)) { - isCompatible = true - break - } - } - assertTrue( - "New UI: getKeyboardLayoutListForInputDevice API should only return " + - "compatible layouts but found " + kl.descriptor, - isCompatible + assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " + + "containing English(US) layout for hi-Latn", + containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR) + ) + assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " + + "containing English(No script code) layout for hi-Latn", + containsLayout( + keyboardLayouts, + createLayoutDescriptor("keyboard_layout_english_without_script_code") ) - } + ) // Check Layouts for "hi" which by default uses 'Deva' script. keyboardLayouts = @@ -600,6 +591,46 @@ class KeyboardLayoutManagerTests { 1, keyboardLayouts.size ) + + // Special case Japanese: UScript ignores provided script code for certain language tags + // Should manually match provided script codes and then rely on Uscript to derive + // script from language tags and match those. + keyboardLayouts = + keyboardLayoutManager.getKeyboardLayoutListForInputDevice( + keyboardDevice.identifier, USER_ID, imeInfo, + createImeSubtypeForLanguageTag("ja-Latn-JP") + ) + assertNotEquals( + "New UI: getKeyboardLayoutListForInputDevice API should return the list of " + + "supported layouts with matching script code for ja-Latn-JP", + 0, + keyboardLayouts.size + ) + assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " + + "containing English(US) layout for ja-Latn-JP", + containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR) + ) + assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " + + "containing English(No script code) layout for ja-Latn-JP", + containsLayout( + keyboardLayouts, + createLayoutDescriptor("keyboard_layout_english_without_script_code") + ) + ) + + // If script code not explicitly provided for Japanese should rely on Uscript to find + // derived script code and hence no suitable layout will be found. + keyboardLayouts = + keyboardLayoutManager.getKeyboardLayoutListForInputDevice( + keyboardDevice.identifier, USER_ID, imeInfo, + createImeSubtypeForLanguageTag("ja-JP") + ) + assertEquals( + "New UI: getKeyboardLayoutListForInputDevice API should return empty list of " + + "supported layouts with matching script code for ja-JP", + 0, + keyboardLayouts.size + ) } } @@ -779,10 +810,10 @@ class KeyboardLayoutManagerTests { private fun createLayoutDescriptor(keyboardName: String): String = "$PACKAGE_NAME/$RECEIVER_NAME/$keyboardName" - private fun areScriptsCompatible(scriptList1: IntArray, scriptList2: IntArray): Boolean { - for (s1 in scriptList1) { - for (s2 in scriptList2) { - if (s1 == s2) return true + private fun containsLayout(layoutList: Array<KeyboardLayout>, layoutDesc: String): Boolean { + for (kl in layoutList) { + if (kl.descriptor.equals(layoutDesc)) { + return true } } return false diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java index 13371cce5fb5..40ecaf1770a9 100644 --- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java @@ -54,6 +54,7 @@ import android.util.Xml; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.content.PackageMonitor; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -264,7 +265,8 @@ public class LocaleManagerBackupRestoreTest { // Locales were restored verify(mMockLocaleManagerService, times(1)).setApplicationLocales(DEFAULT_PACKAGE_NAME, - DEFAULT_USER_ID, DEFAULT_LOCALES, false); + DEFAULT_USER_ID, DEFAULT_LOCALES, false, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); checkStageDataDoesNotExist(DEFAULT_USER_ID); } @@ -280,7 +282,8 @@ public class LocaleManagerBackupRestoreTest { // Locales were restored verify(mMockLocaleManagerService, times(1)).setApplicationLocales(DEFAULT_PACKAGE_NAME, - DEFAULT_USER_ID, DEFAULT_LOCALES, false); + DEFAULT_USER_ID, DEFAULT_LOCALES, false, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); checkStageDataDoesNotExist(DEFAULT_USER_ID); mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, DEFAULT_PACKAGE_NAME, false, @@ -303,7 +306,8 @@ public class LocaleManagerBackupRestoreTest { // Locales were restored verify(mMockLocaleManagerService, times(1)).setApplicationLocales(DEFAULT_PACKAGE_NAME, - DEFAULT_USER_ID, DEFAULT_LOCALES, true); + DEFAULT_USER_ID, DEFAULT_LOCALES, true, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); checkStageDataDoesNotExist(DEFAULT_USER_ID); mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, DEFAULT_PACKAGE_NAME, true, @@ -327,7 +331,8 @@ public class LocaleManagerBackupRestoreTest { // Locales were restored verify(mMockLocaleManagerService, times(1)).setApplicationLocales( - DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, DEFAULT_LOCALES, true); + DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, DEFAULT_LOCALES, true, + FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); checkStageDataDoesNotExist(DEFAULT_USER_ID); mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, DEFAULT_PACKAGE_NAME, true, @@ -369,7 +374,8 @@ public class LocaleManagerBackupRestoreTest { mBackupHelper.stageAndApplyRestoredPayload(out.toByteArray(), DEFAULT_USER_ID); verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameA, DEFAULT_USER_ID, - LocaleList.forLanguageTags(langTagsA), true); + LocaleList.forLanguageTags(langTagsA), true, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); pkgLocalesMap.remove(pkgNameA); @@ -422,11 +428,12 @@ public class LocaleManagerBackupRestoreTest { // Restore locales only for myAppB. verify(mMockLocaleManagerService, times(0)).setApplicationLocales(eq(pkgNameA), anyInt(), - any(), anyBoolean()); + any(), anyBoolean(), anyInt()); verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameB, DEFAULT_USER_ID, - LocaleList.forLanguageTags(langTagsB), true); + LocaleList.forLanguageTags(langTagsB), true, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); verify(mMockLocaleManagerService, times(0)).setApplicationLocales(eq(pkgNameC), anyInt(), - any(), anyBoolean()); + any(), anyBoolean(), anyInt()); // App C is staged. pkgLocalesMap.remove(pkgNameA); @@ -484,7 +491,8 @@ public class LocaleManagerBackupRestoreTest { mPackageMonitor.onPackageAdded(pkgNameA, DEFAULT_UID); verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameA, DEFAULT_USER_ID, - LocaleList.forLanguageTags(langTagsA), false); + LocaleList.forLanguageTags(langTagsA), false, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, pkgNameA, false, false); @@ -499,7 +507,8 @@ public class LocaleManagerBackupRestoreTest { mPackageMonitor.onPackageAdded(pkgNameB, DEFAULT_UID); verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameB, DEFAULT_USER_ID, - LocaleList.forLanguageTags(langTagsB), true); + LocaleList.forLanguageTags(langTagsB), true, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, pkgNameB, true, false); @@ -606,7 +615,8 @@ public class LocaleManagerBackupRestoreTest { mPackageMonitor.onPackageAdded(pkgNameA, DEFAULT_UID); verify(mMockLocaleManagerService, times(1)).setApplicationLocales( - pkgNameA, DEFAULT_USER_ID, LocaleList.forLanguageTags(langTagsA), false); + pkgNameA, DEFAULT_USER_ID, LocaleList.forLanguageTags(langTagsA), false, + FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE); pkgLocalesMap.remove(pkgNameA); @@ -620,7 +630,7 @@ public class LocaleManagerBackupRestoreTest { mPackageMonitor.onPackageAdded(pkgNameB, DEFAULT_UID); verify(mMockLocaleManagerService, times(0)).setApplicationLocales(eq(pkgNameB), anyInt(), - any(), anyBoolean()); + any(), anyBoolean(), anyInt()); checkStageDataDoesNotExist(DEFAULT_USER_ID); } @@ -734,7 +744,7 @@ public class LocaleManagerBackupRestoreTest { */ private void verifyNothingRestored() throws Exception { verify(mMockLocaleManagerService, times(0)).setApplicationLocales(anyString(), anyInt(), - any(), anyBoolean()); + any(), anyBoolean(), anyInt()); } private static void verifyPayloadForAppLocales(Map<String, LocalesInfo> expectedPkgLocalesMap, diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java index 07fda309f03e..550204b99323 100644 --- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java @@ -52,6 +52,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.content.PackageMonitor; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal.PackageConfig; @@ -136,7 +137,8 @@ public class LocaleManagerServiceTest { try { mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, - LocaleList.getEmptyLocaleList(), false); + LocaleList.getEmptyLocaleList(), false, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS); fail("Expected SecurityException"); } finally { verify(mMockContext).enforceCallingOrSelfPermission( @@ -151,7 +153,8 @@ public class LocaleManagerServiceTest { public void testSetApplicationLocales_nullPackageName_fails() throws Exception { try { mLocaleManagerService.setApplicationLocales(/* appPackageName = */ null, - DEFAULT_USER_ID, LocaleList.getEmptyLocaleList(), false); + DEFAULT_USER_ID, LocaleList.getEmptyLocaleList(), false, + FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS); fail("Expected NullPointerException"); } finally { verify(mMockBackupHelper, times(0)).notifyBackupManager(); @@ -165,7 +168,8 @@ public class LocaleManagerServiceTest { try { mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, - /* locales = */ null, false); + /* locales = */ null, false, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS); fail("Expected NullPointerException"); } finally { verify(mMockBackupHelper, times(0)).notifyBackupManager(); @@ -183,7 +187,8 @@ public class LocaleManagerServiceTest { setUpPassingPermissionCheckFor(Manifest.permission.CHANGE_CONFIGURATION); mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, - DEFAULT_LOCALES, true); + DEFAULT_LOCALES, true, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DELEGATE); assertEquals(DEFAULT_LOCALES, mFakePackageConfigurationUpdater.getStoredLocales()); verify(mMockBackupHelper, times(1)).notifyBackupManager(); @@ -196,7 +201,8 @@ public class LocaleManagerServiceTest { .when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt()); mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, - DEFAULT_LOCALES, false); + DEFAULT_LOCALES, false, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS); assertEquals(DEFAULT_LOCALES, mFakePackageConfigurationUpdater.getStoredLocales()); verify(mMockBackupHelper, times(1)).notifyBackupManager(); @@ -208,7 +214,8 @@ public class LocaleManagerServiceTest { .when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt()); try { mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, - LocaleList.getEmptyLocaleList(), false); + LocaleList.getEmptyLocaleList(), false, FrameworkStatsLog + .APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS); fail("Expected IllegalArgumentException"); } finally { assertNoLocalesStored(mFakePackageConfigurationUpdater.getStoredLocales()); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceShellCommandTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceShellCommandTest.java index 32c9e75e1288..697f4d46d16a 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceShellCommandTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceShellCommandTest.java @@ -107,7 +107,7 @@ public class UserManagerServiceShellCommandTest { new String[]{"get-main-user"}, mShellCallback, mResultReceiver)); mWriter.flush(); - assertEquals("Main user id: 12", mOutStream.toString().trim()); + assertEquals("12", mOutStream.toString().trim()); } @Test @@ -118,7 +118,7 @@ public class UserManagerServiceShellCommandTest { assertEquals(1, mCommand.exec(mBinder, in, out, err, new String[]{"get-main-user"}, mShellCallback, mResultReceiver)); mWriter.flush(); - assertEquals("Couldn't get main user.", mOutStream.toString().trim()); + assertEquals("None", mOutStream.toString().trim()); } @Test diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml index e8e3a8f84f21..09ee59816a2c 100644 --- a/services/tests/uiservicestests/AndroidManifest.xml +++ b/services/tests/uiservicestests/AndroidManifest.xml @@ -32,6 +32,7 @@ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" /> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" /> diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java index 182bf949af1f..82bc6f6c5263 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java +++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java @@ -16,8 +16,10 @@ package com.android.server; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.content.Intent; import android.content.pm.PackageManagerInternal; import android.net.Uri; import android.os.Build; @@ -44,8 +46,8 @@ public class UiServiceTestCase { protected static final String PKG_R = "com.example.r"; @Rule - public final TestableContext mContext = - new TestableContext(InstrumentationRegistry.getContext(), null); + public TestableContext mContext = + spy(new TestableContext(InstrumentationRegistry.getContext(), null)); protected TestableContext getContext() { return mContext; @@ -81,6 +83,11 @@ public class UiServiceTestCase { LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal); when(mUgmInternal.checkGrantUriPermission( anyInt(), anyString(), any(Uri.class), anyInt(), anyInt())).thenReturn(-1); + + Mockito.doReturn(new Intent()).when(mContext).registerReceiverAsUser( + any(), any(), any(), any(), any()); + Mockito.doReturn(new Intent()).when(mContext).registerReceiver(any(), any()); + Mockito.doNothing().when(mContext).unregisterReceiver(any()); } @After diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index ce076217f37b..8fcbf2f9e97a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -130,13 +130,18 @@ public class ManagedServicesTest extends UiServiceTestCase { private ArrayMap<Integer, ArrayMap<Integer, String>> mExpectedPrimary; private ArrayMap<Integer, ArrayMap<Integer, String>> mExpectedSecondary; + private UserHandle mUser; + private String mPkg; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - getContext().setMockPackageManager(mPm); - getContext().addMockSystemService(Context.USER_SERVICE, mUm); - getContext().addMockSystemService(DEVICE_POLICY_SERVICE, mDpm); + mContext.setMockPackageManager(mPm); + mContext.addMockSystemService(Context.USER_SERVICE, mUm); + mContext.addMockSystemService(DEVICE_POLICY_SERVICE, mDpm); + mUser = mContext.getUser(); + mPkg = mContext.getPackageName(); List<UserInfo> users = new ArrayList<>(); users.add(mZero); @@ -861,8 +866,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -891,8 +896,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -921,8 +926,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -951,8 +956,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -981,8 +986,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1011,8 +1016,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1437,8 +1442,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1464,8 +1469,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1492,8 +1497,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1522,8 +1527,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1552,8 +1557,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1791,8 +1796,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1837,8 +1842,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); @@ -1880,8 +1885,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ApplicationInfo ai = new ApplicationInfo(); ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - when(context.getPackageName()).thenReturn(mContext.getPackageName()); - when(context.getUserId()).thenReturn(mContext.getUserId()); + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); when(context.getPackageManager()).thenReturn(pm); when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); 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 d73a3b8e44a6..95fae0707304 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java @@ -33,9 +33,11 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Person; +import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.graphics.Color; import android.os.Build; import android.os.UserHandle; @@ -63,7 +65,7 @@ import java.util.List; @SmallTest @RunWith(Parameterized.class) public class NotificationComparatorTest extends UiServiceTestCase { - @Mock Context mContext; + @Mock Context mMockContext; @Mock TelecomManager mTm; @Mock RankingHandler handler; @Mock PackageManager mPm; @@ -115,32 +117,35 @@ public class NotificationComparatorTest extends UiServiceTestCase { int userId = UserHandle.myUserId(); - when(mContext.getResources()).thenReturn(getContext().getResources()); - when(mContext.getTheme()).thenReturn(getContext().getTheme()); - when(mContext.getContentResolver()).thenReturn(getContext().getContentResolver()); - when(mContext.getPackageManager()).thenReturn(mPm); - when(mContext.getSystemService(eq(Context.TELECOM_SERVICE))).thenReturn(mTm); - when(mContext.getSystemService(Vibrator.class)).thenReturn(mVibrator); - when(mContext.getString(anyInt())).thenCallRealMethod(); - when(mContext.getColor(anyInt())).thenCallRealMethod(); + final Resources res = mContext.getResources(); + when(mMockContext.getResources()).thenReturn(res); + final Resources.Theme theme = mContext.getTheme(); + when(mMockContext.getTheme()).thenReturn(theme); + final ContentResolver cr = mContext.getContentResolver(); + when(mMockContext.getContentResolver()).thenReturn(cr); + when(mMockContext.getPackageManager()).thenReturn(mPm); + when(mMockContext.getSystemService(eq(mMockContext.TELECOM_SERVICE))).thenReturn(mTm); + when(mMockContext.getSystemService(Vibrator.class)).thenReturn(mVibrator); + when(mMockContext.getString(anyInt())).thenCallRealMethod(); + when(mMockContext.getColor(anyInt())).thenCallRealMethod(); when(mTm.getDefaultDialerPackage()).thenReturn(callPkg); final ApplicationInfo legacy = new ApplicationInfo(); legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; try { when(mPm.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(legacy); - when(mContext.getApplicationInfo()).thenReturn(legacy); + when(mMockContext.getApplicationInfo()).thenReturn(legacy); } catch (PackageManager.NameNotFoundException e) { // let's hope not } - smsPkg = Settings.Secure.getString(mContext.getContentResolver(), + smsPkg = Settings.Secure.getString(mMockContext.getContentResolver(), Settings.Secure.SMS_DEFAULT_APPLICATION); - Notification nonInterruptiveNotif = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification nonInterruptiveNotif = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_CALL) .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) .build(); - mRecordMinCallNonInterruptive = new NotificationRecord(mContext, + mRecordMinCallNonInterruptive = new NotificationRecord(mMockContext, new StatusBarNotification(callPkg, callPkg, 1, "mRecordMinCallNonInterruptive", callUid, callUid, nonInterruptiveNotif, @@ -148,134 +153,134 @@ public class NotificationComparatorTest extends UiServiceTestCase { mRecordMinCallNonInterruptive.setSystemImportance(NotificationManager.IMPORTANCE_MIN); mRecordMinCallNonInterruptive.setInterruptive(false); - Notification n1 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n1 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_CALL) .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) .build(); - mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg, + mRecordMinCall = new NotificationRecord(mMockContext, new StatusBarNotification(callPkg, callPkg, 1, "minCall", callUid, callUid, n1, new UserHandle(userId), "", 2000), getDefaultChannel()); mRecordMinCall.setSystemImportance(NotificationManager.IMPORTANCE_MIN); mRecordMinCall.setInterruptive(true); - Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n2 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_CALL) .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) .build(); - mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg, + mRecordHighCall = new NotificationRecord(mMockContext, new StatusBarNotification(callPkg, callPkg, 1, "highcall", callUid, callUid, n2, new UserHandle(userId), "", 1999), getDefaultChannel()); mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); - Notification nHighCallStyle = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification nHighCallStyle = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setStyle(Notification.CallStyle.forOngoingCall( new Person.Builder().setName("caller").build(), mock(PendingIntent.class) )) .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) .build(); - mRecordHighCallStyle = new NotificationRecord(mContext, new StatusBarNotification(callPkg, - callPkg, 1, "highCallStyle", callUid, callUid, nHighCallStyle, + mRecordHighCallStyle = new NotificationRecord(mMockContext, new StatusBarNotification( + callPkg, callPkg, 1, "highCallStyle", callUid, callUid, nHighCallStyle, new UserHandle(userId), "", 2000), getDefaultChannel()); mRecordHighCallStyle.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); mRecordHighCallStyle.setInterruptive(true); - Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n4 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setStyle(new Notification.MessagingStyle("sender!")).build(); - mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2, + mRecordInlineReply = new NotificationRecord(mMockContext, new StatusBarNotification(pkg2, pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId), "", 1599), getDefaultChannel()); mRecordInlineReply.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX); if (smsPkg != null) { - Notification n5 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n5 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_MESSAGE).build(); - mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg, + mRecordSms = new NotificationRecord(mMockContext, new StatusBarNotification(smsPkg, smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId), "", 1299), getDefaultChannel()); mRecordSms.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT); } - Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build(); - mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2, + Notification n6 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID).build(); + mRecordStarredContact = new NotificationRecord(mMockContext, new StatusBarNotification(pkg2, pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId), "", 1259), getDefaultChannel()); mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT); mRecordStarredContact.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT); - Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build(); - mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2, + Notification n7 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID).build(); + mRecordContact = new NotificationRecord(mMockContext, new StatusBarNotification(pkg2, pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId), "", 1259), getDefaultChannel()); mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT); mRecordContact.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT); - Notification nSystemMax = new Notification.Builder(mContext, TEST_CHANNEL_ID).build(); - mRecordSystemMax = new NotificationRecord(mContext, new StatusBarNotification(sysPkg, + Notification nSystemMax = new Notification.Builder(mMockContext, TEST_CHANNEL_ID).build(); + mRecordSystemMax = new NotificationRecord(mMockContext, new StatusBarNotification(sysPkg, sysPkg, 1, "systemmax", uid2, uid2, nSystemMax, new UserHandle(userId), "", 1244), getDefaultChannel()); mRecordSystemMax.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); - Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build(); - mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2, + Notification n8 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID).build(); + mRecordUrgent = new NotificationRecord(mMockContext, new StatusBarNotification(pkg2, pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId), "", 1258), getDefaultChannel()); mRecordUrgent.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); - Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n9 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_MESSAGE) .setFlag(Notification.FLAG_ONGOING_EVENT |Notification.FLAG_FOREGROUND_SERVICE, true) .build(); - mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2, + mRecordCheater = new NotificationRecord(mMockContext, new StatusBarNotification(pkg2, pkg2, 1, "cheater", uid2, uid2, n9, new UserHandle(userId), "", 9258), getDefaultChannel()); mRecordCheater.setSystemImportance(NotificationManager.IMPORTANCE_LOW); mRecordCheater.setPackagePriority(Notification.PRIORITY_MAX); - Notification n10 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n10 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setStyle(new Notification.InboxStyle().setSummaryText("message!")).build(); - mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2, + mRecordEmail = new NotificationRecord(mMockContext, new StatusBarNotification(pkg2, pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId), "", 1599), getDefaultChannel()); mRecordEmail.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); - Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n11 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_MESSAGE) .setColorized(true).setColor(Color.WHITE) .build(); - mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2, - pkg2, 1, "cheaterColorized", uid2, uid2, n11, new UserHandle(userId), - "", 9258), getDefaultChannel()); + mRecordCheaterColorized = new NotificationRecord(mMockContext, + new StatusBarNotification(pkg2,pkg2, 1, "cheaterColorized", uid2, uid2, n11, + new UserHandle(userId), "", 9258), getDefaultChannel()); mRecordCheaterColorized.setSystemImportance(NotificationManager.IMPORTANCE_LOW); - Notification n12 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n12 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_MESSAGE) .setColorized(true).setColor(Color.WHITE) .setStyle(new Notification.MediaStyle()) .build(); - mNoMediaSessionMedia = new NotificationRecord(mContext, new StatusBarNotification( + mNoMediaSessionMedia = new NotificationRecord(mMockContext, new StatusBarNotification( pkg2, pkg2, 1, "media", uid2, uid2, n12, new UserHandle(userId), "", 9258), getDefaultChannel()); mNoMediaSessionMedia.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT); - Notification n13 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n13 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) .setColorized(true).setColor(Color.WHITE) .build(); - mRecordColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2, + mRecordColorized = new NotificationRecord(mMockContext, new StatusBarNotification(pkg2, pkg2, 1, "colorized", uid2, uid2, n13, new UserHandle(userId), "", 1999), getDefaultChannel()); mRecordColorized.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); - Notification n14 = new Notification.Builder(mContext, TEST_CHANNEL_ID) + Notification n14 = new Notification.Builder(mMockContext, TEST_CHANNEL_ID) .setCategory(Notification.CATEGORY_CALL) .setColorized(true).setColor(Color.WHITE) .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) .build(); - mRecordColorizedCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg, - callPkg, 1, "colorizedCall", callUid, callUid, n14, + mRecordColorizedCall = new NotificationRecord(mMockContext, new StatusBarNotification( + callPkg, callPkg, 1, "colorizedCall", callUid, callUid, n14, new UserHandle(userId), "", 1999), getDefaultChannel()); mRecordColorizedCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); } @@ -316,14 +321,14 @@ public class NotificationComparatorTest extends UiServiceTestCase { actual.addAll(expected); Collections.shuffle(actual); - Collections.sort(actual, new NotificationComparator(mContext)); + Collections.sort(actual, new NotificationComparator(mMockContext)); assertThat(actual).containsExactlyElementsIn(expected).inOrder(); } @Test public void testRankingScoreOverrides() { - NotificationComparator comp = new NotificationComparator(mContext); + NotificationComparator comp = new NotificationComparator(mMockContext); NotificationRecord recordMinCallNonInterruptive = spy(mRecordMinCallNonInterruptive); if (mSortByInterruptiveness) { assertTrue(comp.compare(mRecordMinCall, recordMinCallNonInterruptive) < 0); @@ -339,7 +344,7 @@ public class NotificationComparatorTest extends UiServiceTestCase { @Test public void testMessaging() { - NotificationComparator comp = new NotificationComparator(mContext); + NotificationComparator comp = new NotificationComparator(mMockContext); assertTrue(comp.isImportantMessaging(mRecordInlineReply)); if (mRecordSms != null) { assertTrue(comp.isImportantMessaging(mRecordSms)); @@ -350,7 +355,7 @@ public class NotificationComparatorTest extends UiServiceTestCase { @Test public void testPeople() { - NotificationComparator comp = new NotificationComparator(mContext); + NotificationComparator comp = new NotificationComparator(mMockContext); assertTrue(comp.isImportantPeople(mRecordStarredContact)); assertTrue(comp.isImportantPeople(mRecordContact)); } 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 1b42fd3bb241..60f1e66b7e94 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java @@ -30,6 +30,7 @@ import android.app.NotificationHistory.HistoricalNotification; import android.content.Context; import android.graphics.drawable.Icon; import android.os.Handler; +import android.os.UserHandle; import android.util.AtomicFile; import androidx.test.InstrumentationRegistry; @@ -56,8 +57,6 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { File mRootDir; @Mock Handler mFileWriteHandler; - @Mock - Context mContext; NotificationHistoryDatabase mDataBase; @@ -92,10 +91,8 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - when(mContext.getUser()).thenReturn(getContext().getUser()); - when(mContext.getPackageName()).thenReturn(getContext().getPackageName()); - - mRootDir = new File(mContext.getFilesDir(), "NotificationHistoryDatabaseTest"); + final File fileDir = mContext.getFilesDir(); + mRootDir = new File(fileDir, "NotificationHistoryDatabaseTest"); mDataBase = new NotificationHistoryDatabase(mFileWriteHandler, mRootDir); mDataBase.init(); 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 02c030d16f6a..42d1ace37ba5 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -73,6 +73,8 @@ import static android.service.notification.NotificationListenerService.FLAG_FILT import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING; @@ -81,6 +83,7 @@ import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.No import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -119,6 +122,7 @@ import static java.util.Collections.singletonList; import android.Manifest; import android.annotation.SuppressLint; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; @@ -276,11 +280,16 @@ import java.util.function.Consumer; @RunWithLooper public class NotificationManagerServiceTest extends UiServiceTestCase { private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"; + private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package"; private static final String PKG_NO_CHANNELS = "com.example.no.channels"; private static final int TEST_TASK_ID = 1; - private static final int UID_HEADLESS = 1000000; + private static final int UID_HEADLESS = 1_000_000; + private static final int TOAST_DURATION = 2_000; + private static final int SECONDARY_DISPLAY_ID = 42; private final int mUid = Binder.getCallingUid(); + private final @UserIdInt int mUserId = UserHandle.getUserId(mUid); + private TestableNotificationManagerService mService; private INotificationManager mBinderService; private NotificationManagerInternal mInternalService; @@ -298,7 +307,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Mock private PermissionHelper mPermissionHelper; private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake(); - private TestableContext mContext = spy(getContext()); private final String PKG = mContext.getPackageName(); private TestableLooper mTestableLooper; @Mock @@ -416,7 +424,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Shell permisssions will override permissions of our app, so add all necessary permissions // for this test here: InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( - "android.permission.ALLOWLISTED_WRITE_DEVICE_CONFIG", + "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG", "android.permission.READ_DEVICE_CONFIG", "android.permission.READ_CONTACTS"); @@ -511,7 +519,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf); mListener = mListeners.new ManagedServiceInfo( null, new ComponentName(PKG, "test_class"), - UserHandle.getUserId(mUid), true, null, 0, 123); + mUserId, true, null, 0, 123); ComponentName defaultComponent = ComponentName.unflattenFromString("config/device"); ArraySet<ComponentName> components = new ArraySet<>(); components.add(defaultComponent); @@ -569,9 +577,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ArgumentCaptor<IntentFilter> intentFilterCaptor = ArgumentCaptor.forClass(IntentFilter.class); - Mockito.doReturn(new Intent()).when(mContext).registerReceiverAsUser( - any(), any(), any(), any(), any()); - Mockito.doReturn(new Intent()).when(mContext).registerReceiver(any(), any()); verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(), any(), intentFilterCaptor.capture(), any(), any()); verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(), @@ -602,6 +607,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), anyString(), anyInt(), any())).thenReturn(true); when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true); + mockIsUserVisible(DEFAULT_DISPLAY, true); + mockIsVisibleBackgroundUsersSupported(false); // Set the testable bubble extractor RankingHelper rankingHelper = mService.getRankingHelper(); @@ -1037,7 +1044,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { new ParceledListSlice(Arrays.asList(channel))); verify(mWorkerHandler).post(eq(new NotificationManagerService .ShowNotificationPermissionPromptRunnable(PKG_NO_CHANNELS, - UserHandle.getUserId(mUid), TEST_TASK_ID, mPermissionPolicyInternal))); + mUserId, TEST_TASK_ID, mPermissionPolicyInternal))); } @Test @@ -1404,7 +1411,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false); verify(mPermissionHelper).setNotificationPermission( - mContext.getPackageName(), UserHandle.getUserId(mUid), false, true); + mContext.getPackageName(), mUserId, false, true); verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt()); List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls(); @@ -3121,7 +3128,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testCreateChannelNotifyListener() throws Exception { - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mService.setPreferencesHelper(mPreferencesHelper); when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(), @@ -3148,7 +3155,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testCreateChannelGroupNotifyListener() throws Exception { - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mService.setPreferencesHelper(mPreferencesHelper); NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b"); @@ -3167,7 +3174,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testUpdateChannelNotifyListener() throws Exception { - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mService.setPreferencesHelper(mPreferencesHelper); mTestNotificationChannel.setLightColor(Color.CYAN); @@ -3184,7 +3191,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testDeleteChannelNotifyListener() throws Exception { - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mService.setPreferencesHelper(mPreferencesHelper); when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(), @@ -3201,7 +3208,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception { - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mService.setPreferencesHelper(mPreferencesHelper); when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(), @@ -3215,7 +3222,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testDeleteChannelGroupNotifyListener() throws Exception { - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c"); mService.setPreferencesHelper(mPreferencesHelper); @@ -3231,7 +3238,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testDeleteChannelGroupChecksForFgses() throws Exception { - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); CountDownLatch latch = new CountDownLatch(2); mService.createNotificationChannelGroup( @@ -3280,7 +3287,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean())) @@ -3300,7 +3307,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(emptyList()); try { @@ -3322,7 +3329,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mListener = mock(ManagedServices.ManagedServiceInfo.class); mListener.component = new ComponentName(PKG, PKG); @@ -3348,7 +3355,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mBinderService.getNotificationChannelsFromPrivilegedListener( @@ -3361,7 +3368,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(emptyList()); try { @@ -3380,7 +3387,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testGetNotificationChannelFromPrivilegedListener_assistant_success() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(emptyList()); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); @@ -3395,7 +3402,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(emptyList()); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); @@ -3414,7 +3421,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mListener = mock(ManagedServices.ManagedServiceInfo.class); when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); @@ -3435,7 +3442,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(singletonList(mock(AssociationInfo.class))); mBinderService.getNotificationChannelGroupsFromPrivilegedListener( @@ -3447,7 +3454,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(emptyList()); try { @@ -3464,7 +3471,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); - when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + when(mCompanionMgr.getAssociations(PKG, mUserId)) .thenReturn(emptyList()); mListener = mock(ManagedServices.ManagedServiceInfo.class); when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); @@ -4536,7 +4543,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Same notifications are enqueued as posted, everything counts b/c id and tag don't match // anything that's currently enqueued or posted - int userId = UserHandle.getUserId(mUid); + int userId = mUserId; assertEquals(40, mService.getNotificationCount(PKG, userId, 0, null)); assertEquals(40, @@ -6530,7 +6537,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); // notifications from this package are blocked by the user @@ -6539,8 +6546,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, true); // enqueue toast -> toast should still enqueue - ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(), - new TestableToastCallback(), 2000, 0); + enqueueToast(testPackage, new TestableToastCallback()); assertEquals(1, mService.mToastQueue.size()); } @@ -6553,14 +6559,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, false); // enqueue toast -> no toasts enqueued - ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(), - new TestableToastCallback(), 2000, 0); + enqueueToast(testPackage, new TestableToastCallback()); assertEquals(0, mService.mToastQueue.size()); } @@ -6573,7 +6578,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, true); @@ -6583,12 +6588,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { INotificationManager nmService = (INotificationManager) mService.mService; // first time trying to show the toast, showToast gets called - nmService.enqueueToast(testPackage, token, callback, 2000, 0); + enqueueToast(nmService, testPackage, token, callback); verify(callback, times(1)).show(any()); // second time trying to show the same toast, showToast isn't called again (total number of // invocations stays at one) - nmService.enqueueToast(testPackage, token, callback, 2000, 0); + enqueueToast(nmService, testPackage, token, callback); verify(callback, times(1)).show(any()); } @@ -6602,7 +6607,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, true); @@ -6611,7 +6616,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ITransientNotification callback = mock(ITransientNotification.class); INotificationManager nmService = (INotificationManager) mService.mService; - nmService.enqueueToast(testPackage, token, callback, 2000, 0); + enqueueToast(nmService, testPackage, token, callback); verify(callback, times(1)).show(any()); } @@ -6625,7 +6630,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, true); @@ -6636,8 +6641,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ITransientNotification callback2 = mock(ITransientNotification.class); INotificationManager nmService = (INotificationManager) mService.mService; - nmService.enqueueToast(testPackage, token1, callback1, 2000, 0); - nmService.enqueueToast(testPackage, token2, callback2, 2000, 0); + enqueueToast(nmService, testPackage, token1, callback1); + enqueueToast(nmService, testPackage, token2, callback2); assertEquals(2, mService.mToastQueue.size()); // Both toasts enqueued. verify(callback1, times(1)).show(any()); // First toast shown. @@ -6659,14 +6664,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, true); // enqueue toast -> toast should still enqueue - ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), - "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); assertEquals(1, mService.mToastQueue.size()); } @@ -6679,14 +6683,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, false); // enqueue toast -> toast should still enqueue - ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), - "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); assertEquals(1, mService.mToastQueue.size()); } @@ -6699,7 +6702,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, true); @@ -6708,13 +6711,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { INotificationManager nmService = (INotificationManager) mService.mService; // first time trying to show the toast, showToast gets called - nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); verify(mStatusBar, times(1)) .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); // second time trying to show the same toast, showToast isn't called again (total number of // invocations stays at one) - nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); verify(mStatusBar, times(1)) .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); } @@ -6730,13 +6733,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); Binder token = new Binder(); INotificationManager nmService = (INotificationManager) mService.mService; - nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); verify(mStatusBar, times(0)) .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); } @@ -6752,13 +6755,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, true); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); Binder token = new Binder(); INotificationManager nmService = (INotificationManager) mService.mService; - nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); verify(mStatusBar, times(1)) .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); } @@ -6773,13 +6776,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); Binder token = new Binder(); INotificationManager nmService = (INotificationManager) mService.mService; - nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); } @@ -6794,13 +6797,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); Binder token = new Binder(); INotificationManager nmService = (INotificationManager) mService.mService; - nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); // window token was added when enqueued ArgumentCaptor<Binder> binderCaptor = @@ -6827,7 +6830,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); // notifications from this package are blocked by the user @@ -6836,8 +6839,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, false); // enqueue toast -> toast should still enqueue - ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(), - new TestableToastCallback(), 2000, 0); + enqueueToast(testPackage, new TestableToastCallback()); assertEquals(1, mService.mToastQueue.size()); verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any()); } @@ -6852,14 +6854,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, true); // enqueue toast -> toast should still enqueue - ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), - "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); assertEquals(1, mService.mToastQueue.size()); verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); } @@ -6874,35 +6875,117 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); setAppInForegroundForToasts(mUid, false); // enqueue toast -> toast should still enqueue - ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), - "Text", 2000, 0, null); + enqueueTextToast(testPackage, "Text"); assertEquals(1, mService.mToastQueue.size()); verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); } @Test public void testTextToastsCallStatusBar() throws Exception { + allowTestPackageToToast(); + + // enqueue toast -> no toasts enqueued + enqueueTextToast(TEST_PACKAGE, "Text"); + + verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); + } + + @Test + public void testTextToastsCallStatusBar_nonUiContext_defaultDisplay() + throws Exception { + allowTestPackageToToast(); + + enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); + + verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); + } + + @Test + public void testTextToastsCallStatusBar_nonUiContext_secondaryDisplay() + throws Exception { + allowTestPackageToToast(); + mockIsUserVisible(SECONDARY_DISPLAY_ID, true); + + enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); + + verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); + } + + @Test + public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay() + throws Exception { + mockIsVisibleBackgroundUsersSupported(true); + mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); + allowTestPackageToToast(); + + enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, DEFAULT_DISPLAY); + + verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); + + } + + @Test + public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay() + throws Exception { + mockIsVisibleBackgroundUsersSupported(true); + mockIsUserVisible(SECONDARY_DISPLAY_ID, true); + mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used + allowTestPackageToToast(); + + enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, SECONDARY_DISPLAY_ID); + + verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); + } + + @Test + public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay() + throws Exception { + mockIsVisibleBackgroundUsersSupported(true); + mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); + allowTestPackageToToast(); + + enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); + + verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); + } + + @Test + public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay() + throws Exception { + mockIsVisibleBackgroundUsersSupported(true); + mockIsUserVisible(SECONDARY_DISPLAY_ID, true); + mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used + allowTestPackageToToast(); + + enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); + + verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); + } + + @Test + public void testTextToastsCallStatusBar_userNotVisibleOnDisplay() throws Exception { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); + mockIsUserVisible(DEFAULT_DISPLAY, false); // package is not suspended when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) .thenReturn(false); // enqueue toast -> no toasts enqueued - ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), - "Text", 2000, 0, null); - verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), + enqueueTextToast(testPackage, "Text"); + verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); + assertEquals(0, mService.mToastQueue.size()); } @Test @@ -6914,15 +6997,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(true); // notifications from this package are NOT blocked by the user when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); // enqueue toast -> no toasts enqueued - ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(), - new TestableToastCallback(), 2000, 0); + enqueueToast(testPackage, new TestableToastCallback()); + verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), + anyInt()); assertEquals(0, mService.mToastQueue.size()); } @@ -6935,7 +7019,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); // notifications from this package are blocked by the user @@ -6944,8 +7028,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, false); // enqueue toast -> no toasts enqueued - ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(), - new TestableToastCallback(), 2000, 0); + enqueueToast(testPackage, new TestableToastCallback()); assertEquals(0, mService.mToastQueue.size()); } @@ -6958,7 +7041,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(true); // notifications from this package ARE blocked by the user @@ -6967,8 +7050,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setAppInForegroundForToasts(mUid, false); // enqueue toast -> system toast can still be enqueued - ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(), - new TestableToastCallback(), 2000, 0); + enqueueToast(testPackage, new TestableToastCallback()); assertEquals(1, mService.mToastQueue.size()); } @@ -6981,20 +7063,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) .thenReturn(false); INotificationManager nmService = (INotificationManager) mService.mService; // Trying to quickly enqueue more toast than allowed. for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) { - nmService.enqueueTextToast( - testPackage, - new Binder(), - "Text", - /* duration */ 2000, - /* displayId */ 0, - /* callback */ null); + enqueueTextToast(testPackage, "Text"); } // Only allowed number enqueued, rest ignored. assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size()); @@ -7017,7 +7093,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private void setIfPackageHasPermissionToAvoidToastRateLimiting( String pkg, boolean hasPermission) throws Exception { when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS, - pkg, UserHandle.getUserId(mUid))) + pkg, mUserId)) .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED); } @@ -9626,7 +9702,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception { int uid = 9000; - int[] userIds = new int[] {UserHandle.getUserId(mUid), 1000}; + int[] userIds = new int[] {mUserId, 1000}; when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); for (int userId : userIds) { @@ -9658,10 +9734,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception { - int[] userIds = new int[] {UserHandle.getUserId(mUid)}; + int[] userIds = new int[] {mUserId}; when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); List<String> disallowedApps = ImmutableList.of("apples"); - when(mPackageManager.getPackageUid("apples", 0, UserHandle.getUserId(mUid))) + when(mPackageManager.getPackageUid("apples", 0, mUserId)) .thenReturn(1001); when(mListeners.getNotificationListenerFilter(any())).thenReturn(null); @@ -9679,10 +9755,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testMigrateNotificationFilter_existingTypeFilter() throws Exception { - int[] userIds = new int[] {UserHandle.getUserId(mUid)}; + int[] userIds = new int[] {mUserId}; when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); List<String> disallowedApps = ImmutableList.of("apples"); - when(mPackageManager.getPackageUid("apples", 0, UserHandle.getUserId(mUid))) + when(mPackageManager.getPackageUid("apples", 0, mUserId)) .thenReturn(1001); when(mListeners.getNotificationListenerFilter(any())).thenReturn( @@ -9702,10 +9778,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testMigrateNotificationFilter_existingPkgFilter() throws Exception { - int[] userIds = new int[] {UserHandle.getUserId(mUid)}; + int[] userIds = new int[] {mUserId}; when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); List<String> disallowedApps = ImmutableList.of("apples"); - when(mPackageManager.getPackageUid("apples", 0, UserHandle.getUserId(mUid))) + when(mPackageManager.getPackageUid("apples", 0, mUserId)) .thenReturn(1001); NotificationListenerFilter preexisting = new NotificationListenerFilter(); @@ -10718,4 +10794,52 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { String.valueOf(isOn), /* makeDefault= */ false); } + + private void allowTestPackageToToast() throws Exception { + assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty(); + mService.isSystemUid = false; + setToastRateIsWithinQuota(true); + setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false); + // package is not suspended + when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId)) + .thenReturn(false); + } + + private void enqueueToast(String testPackage, ITransientNotification callback) + throws RemoteException { + enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), callback); + } + + private void enqueueToast(INotificationManager service, String testPackage, + IBinder token, ITransientNotification callback) throws RemoteException { + service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ true, + DEFAULT_DISPLAY); + } + + private void enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { + enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY); + } + + private void enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, + int displayId) throws RemoteException { + ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), text, + TOAST_DURATION, isUiContext, displayId, /* textCallback= */ null); + } + + private void mockIsVisibleBackgroundUsersSupported(boolean supported) { + when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported); + } + + private void mockIsUserVisible(int displayId, boolean visible) { + when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible); + } + + private void mockDisplayAssignedToUser(int displayId) { + when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId); + } + + private void verifyToastShownForTestPackage(String text, int displayId) { + verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(), + eq(TOAST_DURATION), any(), eq(displayId)); + } } 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 25e74bf5dcd2..fae92d9ac738 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -55,6 +55,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.Icon; import android.media.AudioAttributes; @@ -126,7 +127,8 @@ public class NotificationRecordTest extends UiServiceTestCase { MockitoAnnotations.initMocks(this); when(mMockContext.getSystemService(eq(Vibrator.class))).thenReturn(mVibrator); - when(mMockContext.getResources()).thenReturn(getContext().getResources()); + final Resources res = mContext.getResources(); + when(mMockContext.getResources()).thenReturn(res); when(mMockContext.getPackageManager()).thenReturn(mPm); when(mMockContext.getContentResolver()).thenReturn(mContentResolver); ApplicationInfo appInfo = new ApplicationInfo(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java index fcff228fb591..0222bfbf8605 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java @@ -67,7 +67,6 @@ import java.util.List; public class NotificationShellCmdTest extends UiServiceTestCase { private final Binder mBinder = new Binder(); private final ShellCallback mCallback = new ShellCallback(); - private final TestableContext mTestableContext = spy(getContext()); @Mock NotificationManagerService mMockService; @Mock @@ -82,7 +81,7 @@ public class NotificationShellCmdTest extends UiServiceTestCase { mTestableLooper = TestableLooper.get(this); mResultReceiver = new ResultReceiver(new Handler(mTestableLooper.getLooper())); - when(mMockService.getContext()).thenReturn(mTestableContext); + when(mMockService.getContext()).thenReturn(mContext); when(mMockService.getBinderService()).thenReturn(mMockBinderService); } @@ -116,9 +115,10 @@ public class NotificationShellCmdTest extends UiServiceTestCase { Notification captureNotification(String aTag) throws Exception { ArgumentCaptor<Notification> notificationCaptor = ArgumentCaptor.forClass(Notification.class); + final String pkg = getContext().getPackageName(); verify(mMockBinderService).enqueueNotificationWithTag( - eq(getContext().getPackageName()), - eq(getContext().getPackageName()), + eq(pkg), + eq(pkg), eq(aTag), eq(NotificationShellCmd.NOTIFICATION_ID), notificationCaptor.capture(), diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 50e5bbf4ba9b..f6d10b9f371c 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -4967,11 +4967,17 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testPullPackagePreferencesStats_postPermissionMigration() { + // make sure there's at least one channel for each package we want to test + NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channelA, true, false); + NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false); + NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_P, UID_P, channelC, true, false); - // build a collection of app permissions that should be passed in but ignored + // build a collection of app permissions that should be passed in and used ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); - appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs - appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, true)); // not in local prefs + appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false)); appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, true)); // in local prefs // local preferences @@ -4981,16 +4987,17 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected output. format: uid -> importance, as only uid (and not package name) // is in PackageNotificationPreferences ArrayMap<Integer, Pair<Integer, Boolean>> expected = new ArrayMap<>(); - expected.put(1, new Pair<>(IMPORTANCE_DEFAULT, false)); - expected.put(3, new Pair<>(IMPORTANCE_NONE, true)); - expected.put(UID_O, new Pair<>(IMPORTANCE_NONE, true)); // banned by permissions - expected.put(UID_P, new Pair<>(IMPORTANCE_NONE, false)); // defaults to none, false + expected.put(UID_N_MR1, new Pair<>(IMPORTANCE_DEFAULT, false)); + expected.put(UID_O, new Pair<>(IMPORTANCE_NONE, true)); // banned by permissions + expected.put(UID_P, new Pair<>(IMPORTANCE_UNSPECIFIED, false)); // default: unspecified ArrayList<StatsEvent> events = new ArrayList<>(); mHelper.pullPackagePreferencesStats(events, appPermissions); + int found = 0; for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { if (builder.getAtomId() == PACKAGE_NOTIFICATION_PREFERENCES) { + ++found; int uid = builder.getInt(PackageNotificationPreferences.UID_FIELD_NUMBER); boolean userSet = builder.getBoolean( PackageNotificationPreferences.USER_SET_IMPORTANCE_FIELD_NUMBER); @@ -5002,6 +5009,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertThat(expected.get(uid).second).isEqualTo(userSet); } } + // should have at least one entry for each of the packages we expected to see + assertThat(found).isAtLeast(3); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index bf836ae0eba0..6f9798ea7d69 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -153,7 +153,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { private Resources mResources; private TestableLooper mTestableLooper; private ZenModeHelper mZenModeHelperSpy; - private Context mContext; private ContentResolver mContentResolver; @Mock AppOpsManager mAppOps; private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory; @@ -163,9 +162,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); - mContext = spy(getContext()); mContentResolver = mContext.getContentResolver(); mResources = spy(mContext.getResources()); + String pkg = mContext.getPackageName(); try { when(mResources.getXml(R.xml.default_zen_mode_config)).thenReturn( getDefaultConfigParser()); @@ -190,7 +189,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { when(mPackageManager.getPackageUidAsUser(eq(CUSTOM_PKG_NAME), anyInt())) .thenReturn(CUSTOM_PKG_UID); when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( - new String[] {getContext().getPackageName()}); + new String[] {pkg}); mZenModeHelperSpy.mPm = mPackageManager; } diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java index 8694094ce6ac..4d3c26f4973e 100644 --- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java +++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingTest.java @@ -37,6 +37,7 @@ import android.os.BatteryStatsInternal; import android.os.Process; import android.os.RemoteException; +import androidx.test.filters.FlakyTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.internal.util.FakeLatencyTracker; @@ -93,10 +94,12 @@ public class SoundTriggerMiddlewareLoggingTest { } @Test + @FlakyTest(bugId = 275113847) public void testSetUpAndTearDown() { } @Test + @FlakyTest(bugId = 275113847) public void testOnPhraseRecognitionStartsLatencyTrackerWithSuccessfulPhraseIdTrigger() throws RemoteException { ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass( @@ -112,6 +115,7 @@ public class SoundTriggerMiddlewareLoggingTest { } @Test + @FlakyTest(bugId = 275113847) public void testOnPhraseRecognitionRestartsActiveSession() throws RemoteException { ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass( ISoundTriggerCallback.class); @@ -131,6 +135,7 @@ public class SoundTriggerMiddlewareLoggingTest { } @Test + @FlakyTest(bugId = 275113847) public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNonSuccessEvent() throws RemoteException { ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass( @@ -147,6 +152,7 @@ public class SoundTriggerMiddlewareLoggingTest { } @Test + @FlakyTest(bugId = 275113847) public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNoKeyphraseId() throws RemoteException { ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass( diff --git a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java index 49af2c1dc681..5863e9d9243a 100644 --- a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java @@ -20,6 +20,7 @@ import static android.view.KeyEvent.KEYCODE_VOLUME_UP; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS; +import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_POWER_DREAM_OR_SLEEP; import android.provider.Settings; import android.view.Display; @@ -49,6 +50,32 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase { } /** + * Power single press to start dreaming when so configured. + */ + @Test + public void testPowerSinglePressRequestsDream() { + mPhoneWindowManager.overrideShortPressOnPower(SHORT_PRESS_POWER_DREAM_OR_SLEEP); + mPhoneWindowManager.overrideCanStartDreaming(true); + sendKey(KEYCODE_POWER); + mPhoneWindowManager.assertDreamRequest(); + mPhoneWindowManager.assertLockedAfterAppTransitionFinished(); + } + + /** + * Power double-press to launch camera does not lock device when the single press behavior is to + * dream. + */ + @Test + public void testPowerDoublePressWillNotLockDevice() { + mPhoneWindowManager.overrideShortPressOnPower(SHORT_PRESS_POWER_DREAM_OR_SLEEP); + mPhoneWindowManager.overrideCanStartDreaming(false); + sendKey(KEYCODE_POWER); + sendKey(KEYCODE_POWER); + mPhoneWindowManager.assertCameraLaunch(); + mPhoneWindowManager.assertWillNotLockAfterAppTransitionFinished(); + } + + /** * Power double press to trigger camera. */ @Test diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java index b6939747a7b6..a2ee8a45433d 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -84,6 +84,7 @@ import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.DisplayPolicy; import com.android.server.wm.DisplayRotation; import com.android.server.wm.WindowManagerInternal; +import com.android.server.wm.WindowManagerInternal.AppTransitionListener; import junit.framework.Assert; @@ -289,6 +290,10 @@ class TestPhoneWindowManager { } } + void overrideShortPressOnPower(int behavior) { + mPhoneWindowManager.mShortPressOnPowerBehavior = behavior; + } + // Override assist perform function. void overrideLongPressOnPower(int behavior) { mPhoneWindowManager.mLongPressOnPowerBehavior = behavior; @@ -311,6 +316,10 @@ class TestPhoneWindowManager { } } + void overrideCanStartDreaming(boolean canDream) { + doReturn(canDream).when(mDreamManagerInternal).canStartDreaming(anyBoolean()); + } + void overrideDisplayState(int state) { doReturn(state).when(mDisplay).getState(); Mockito.reset(mPowerManager); @@ -374,6 +383,10 @@ class TestPhoneWindowManager { timeout(SHORTCUT_KEY_DELAY_MILLIS)).performAccessibilityShortcut(); } + void assertDreamRequest() { + verify(mDreamManagerInternal).requestDream(); + } + void assertPowerSleep() { waitForIdle(); verify(mPowerManager, @@ -454,4 +467,17 @@ class TestPhoneWindowManager { waitForIdle(); verify(mInputManagerInternal).toggleCapsLock(anyInt()); } + + void assertWillNotLockAfterAppTransitionFinished() { + Assert.assertFalse(mPhoneWindowManager.mLockAfterAppTransitionFinished); + } + + void assertLockedAfterAppTransitionFinished() { + ArgumentCaptor<AppTransitionListener> transitionCaptor = + ArgumentCaptor.forClass(AppTransitionListener.class); + verify(mWindowManagerInternal).registerAppTransitionListener( + transitionCaptor.capture()); + transitionCaptor.getValue().onAppTransitionFinishedLocked(any()); + verify(mPhoneWindowManager).lockNow(null); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index b80c3e84198b..17ae215c2930 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -26,25 +26,31 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.window.BackNavigationInfo.typeToString; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.content.Context; +import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; +import android.content.res.Resources; import android.os.Bundle; import android.os.RemoteCallback; import android.os.RemoteException; @@ -58,6 +64,7 @@ import android.window.IOnBackInvokedCallback; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.OnBackInvokedDispatcher; +import android.window.TaskSnapshot; import android.window.WindowOnBackInvokedDispatcher; import com.android.server.LocalServices; @@ -66,6 +73,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -80,11 +89,12 @@ public class BackNavigationControllerTests extends WindowTestsBase { @Before public void setUp() throws Exception { - mBackNavigationController = Mockito.spy(new BackNavigationController()); + final BackNavigationController original = new BackNavigationController(); + original.setWindowManager(mWm); + mBackNavigationController = Mockito.spy(original); LocalServices.removeServiceForTest(WindowManagerInternal.class); mWindowManagerInternal = mock(WindowManagerInternal.class); LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal); - mBackNavigationController.setWindowManager(mWm); mBackAnimationAdapter = mock(BackAnimationAdapter.class); mRootHomeTask = initHomeActivity(); } @@ -120,7 +130,9 @@ public class BackNavigationControllerTests extends WindowTestsBase { // verify if back animation would start. assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation()); - // reset drawning status + // reset drawing status + backNavigationInfo.onBackNavigationFinished(false); + mBackNavigationController.clearBackAnimations(); topTask.forAllWindows(w -> { makeWindowVisibleAndDrawn(w); }, true); @@ -129,6 +141,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); + backNavigationInfo.onBackNavigationFinished(false); + mBackNavigationController.clearBackAnimations(); doReturn(true).when(recordA).canShowWhenLocked(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) @@ -185,6 +199,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation()); // reset drawing status + backNavigationInfo.onBackNavigationFinished(false); + mBackNavigationController.clearBackAnimations(); testCase.recordFront.forAllWindows(w -> { makeWindowVisibleAndDrawn(w); }, true); @@ -193,6 +209,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); + backNavigationInfo.onBackNavigationFinished(false); + mBackNavigationController.clearBackAnimations(); doReturn(true).when(testCase.recordBack).canShowWhenLocked(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) @@ -231,6 +249,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME)); + backNavigationInfo.onBackNavigationFinished(false); + mBackNavigationController.clearBackAnimations(); setupKeyguardOccluded(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) @@ -408,6 +428,25 @@ public class BackNavigationControllerTests extends WindowTestsBase { 0, navigationObserver.getCount()); } + + /** + * Test with + * config_predictShowStartingSurface = true + */ + @Test + public void testEnableWindowlessSurface() { + testPrepareAnimation(true); + } + + /** + * Test with + * config_predictShowStartingSurface = false + */ + @Test + public void testDisableWindowlessSurface() { + testPrepareAnimation(false); + } + private IOnBackInvokedCallback withSystemCallback(Task task) { IOnBackInvokedCallback callback = createOnBackInvokedCallback(); task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo( @@ -492,6 +531,56 @@ public class BackNavigationControllerTests extends WindowTestsBase { doReturn(true).when(kc).isDisplayOccluded(anyInt()); } + private void testPrepareAnimation(boolean preferWindowlessSurface) { + final TaskSnapshot taskSnapshot = mock(TaskSnapshot.class); + final ContextWrapper contextSpy = Mockito.spy(new ContextWrapper(mWm.mContext)); + final Resources resourcesSpy = Mockito.spy(contextSpy.getResources()); + + when(contextSpy.getResources()).thenReturn(resourcesSpy); + + MockitoSession mockitoSession = mockitoSession().mockStatic(BackNavigationController.class) + .strictness(Strictness.LENIENT).startMocking(); + doReturn(taskSnapshot).when(() -> BackNavigationController.getSnapshot(any())); + when(resourcesSpy.getBoolean( + com.android.internal.R.bool.config_predictShowStartingSurface)) + .thenReturn(preferWindowlessSurface); + + final BackNavigationController.AnimationHandler animationHandler = + Mockito.spy(new BackNavigationController.AnimationHandler(mWm)); + doReturn(true).when(animationHandler).isSupportWindowlessSurface(); + testWithConfig(animationHandler, preferWindowlessSurface); + mockitoSession.finishMocking(); + } + + private void testWithConfig(BackNavigationController.AnimationHandler animationHandler, + boolean preferWindowlessSurface) { + final Task task = createTask(mDefaultDisplay); + final ActivityRecord bottomActivity = createActivityRecord(task); + final ActivityRecord homeActivity = mRootHomeTask.getTopNonFinishingActivity(); + + final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toHomeBuilder = + animationHandler.prepareAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME, + mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, homeActivity); + assertTrue(toHomeBuilder.mIsLaunchBehind); + toHomeBuilder.build(); + verify(animationHandler, never()).createStartingSurface(any()); + animationHandler.clearBackAnimateTarget(); + + // Back to ACTIVITY and TASK have the same logic, just with different target. + final ActivityRecord topActivity = createActivityRecord(task); + final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toActivityBuilder = + animationHandler.prepareAnimation( + BackNavigationInfo.TYPE_CROSS_ACTIVITY, mBackAnimationAdapter, task, task, + topActivity, bottomActivity); + assertFalse(toActivityBuilder.mIsLaunchBehind); + toActivityBuilder.build(); + if (preferWindowlessSurface) { + verify(animationHandler).createStartingSurface(any()); + } else { + verify(animationHandler, never()).createStartingSurface(any()); + } + } + @NonNull private Task createTopTaskWithActivity() { Task task = createTask(mDefaultDisplay); 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 695a72e56232..7a0961d8c306 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -202,7 +202,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { // Exclude comparing IME insets because currently the simulated layout only focuses on the // insets from status bar and navigation bar. realInsetsState.removeSource(InsetsSource.ID_IME); - realInsetsState.removeSource(InsetsState.ITYPE_CAPTION_BAR); assertEquals(new ToStringComparatorWrapper<>(realInsetsState), new ToStringComparatorWrapper<>(simulatedInsetsState)); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 226ecf421928..146ed34204f5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -792,7 +792,7 @@ public class DisplayRotationTests { // ... until half-fold mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED); assertTrue(waitForUiHandler()); - verify(sMockWm).updateRotation(anyBoolean(), anyBoolean()); + verify(sMockWm).updateRotation(false, false); assertTrue(waitForUiHandler()); assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation( SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); @@ -800,7 +800,7 @@ public class DisplayRotationTests { // ... then transition back to flat mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN); assertTrue(waitForUiHandler()); - verify(sMockWm, atLeast(1)).updateRotation(anyBoolean(), anyBoolean()); + verify(sMockWm, atLeast(1)).updateRotation(false, false); assertTrue(waitForUiHandler()); assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); diff --git a/services/voiceinteraction/OWNERS b/services/voiceinteraction/OWNERS index ef1061b28b63..40e8d26931e1 100644 --- a/services/voiceinteraction/OWNERS +++ b/services/voiceinteraction/OWNERS @@ -1 +1,2 @@ include /core/java/android/service/voice/OWNERS +include /media/java/android/media/soundtrigger/OWNERS diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS b/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS index 01b2cb981bbb..1e41886fe716 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS @@ -1,2 +1 @@ -atneya@google.com -elaurent@google.com +include /media/java/android/media/soundtrigger/OWNERS diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 3eabea67e890..48a39e682340 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -621,8 +621,13 @@ final class HotwordDetectionConnection { ServiceConnectionFactory(@NonNull Intent intent, boolean bindInstantServiceAllowed, int detectionServiceType) { mIntent = intent; - mBindingFlags = bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0; mDetectionServiceType = detectionServiceType; + int flags = bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0; + if (mVisualQueryDetectionComponentName != null + && mHotwordDetectionComponentName != null) { + flags |= Context.BIND_SHARED_ISOLATED_PROCESS; + } + mBindingFlags = flags; } ServiceConnection createLocked() { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 929e033315f7..62be2a555bc4 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -738,6 +738,13 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } else { verifyDetectorForVisualQueryDetectionLocked(sharedMemory); } + if (!verifyProcessSharingLocked()) { + Slog.w(TAG, "Sandboxed detection service not in shared isolated process"); + throw new IllegalStateException("VisualQueryDetectionService or HotworDetectionService " + + "not in a shared isolated process. Please make sure to set " + + "android:allowSharedIsolatedProcess and android:isolatedProcess to be true " + + "and android:externalService to be false in the manifest file"); + } if (mHotwordDetectionConnection == null) { mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext, @@ -931,6 +938,19 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0 && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0; } + @GuardedBy("this") + boolean verifyProcessSharingLocked() { + // only check this if both VQDS and HDS are declared in the app + ServiceInfo hotwordInfo = getServiceInfoLocked(mHotwordDetectionComponentName, mUser); + ServiceInfo visualQueryInfo = + getServiceInfoLocked(mVisualQueryDetectionComponentName, mUser); + if (hotwordInfo == null || visualQueryInfo == null) { + return true; + } + return (hotwordInfo.flags & ServiceInfo.FLAG_ALLOW_SHARED_ISOLATED_PROCESS) != 0 + && (visualQueryInfo.flags & ServiceInfo.FLAG_ALLOW_SHARED_ISOLATED_PROCESS) != 0; + } + void forceRestartHotwordDetector() { if (mHotwordDetectionConnection == null) { diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java index 884dcf2dfbad..a34094ce6452 100644 --- a/telecomm/java/android/telecom/Log.java +++ b/telecomm/java/android/telecom/Log.java @@ -69,6 +69,7 @@ public class Log { private static final Object sSingletonSync = new Object(); private static EventManager sEventManager; private static SessionManager sSessionManager; + private static Object sLock = null; /** * Tracks whether user-activated extended logging is enabled. @@ -388,6 +389,19 @@ public class Log { } /** + * Sets the main telecom sync lock used within Telecom. This is used when building log messages + * so that we can identify places in the code where we are doing something outside of the + * Telecom lock. + * @param lock The lock. + */ + public static void setLock(Object lock) { + // Don't do lock monitoring on user builds. + if (!Build.IS_USER) { + sLock = lock; + } + } + + /** * If user enabled extended logging is enabled and the time limit has passed, disables the * extended logging. */ @@ -512,7 +526,10 @@ public class Log { args.length); msg = format + " (An error occurred while formatting the message.)"; } - return String.format(Locale.US, "%s: %s%s", prefix, msg, sessionPostfix); + // If a lock was set, check if this thread holds that lock and output an emoji that lets + // the developer know whether a log message came from within the Telecom lock or not. + String isLocked = sLock != null ? (Thread.holdsLock(sLock) ? "\uD83D\uDD12" : "❗") : ""; + return String.format(Locale.US, "%s: %s%s%s", prefix, msg, sessionPostfix, isLocked); } /** diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index ba4a54e508ef..7abae1854025 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4586,6 +4586,57 @@ public class CarrierConfigManager { "data_stall_recovery_should_skip_bool_array"; /** + * String array containing the list of names for service numbers provided by carriers. This key + * should be used with {@link #KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY}. The names provided in + * this array will be mapped 1:1 with the numbers provided in the {@link + * #KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY} array. + * + * <p>The data would be considered valid if and only if: + * + * <ul> + * <li>The number of items in both the arrays are equal + * <li>The data added to the {@link #KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY} array is valid. + * See {@link #KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY} for more information. + * </ul> + * + * <p>Example: + * + * <pre><code> + * <string-array name="carrier_service_name_array" num="2"> + * <item value="Police"/> + * <item value="Ambulance"/> + * </string-array> + * </code></pre> + */ + public static final String KEY_CARRIER_SERVICE_NAME_STRING_ARRAY = "carrier_service_name_array"; + + /** + * String array containing the list of service numbers provided by carriers. This key should be + * used with {@link #KEY_CARRIER_SERVICE_NAME_STRING_ARRAY}. The numbers provided in this array + * will be mapped 1:1 with the names provided in the {@link + * #KEY_CARRIER_SERVICE_NAME_STRING_ARRAY} array. + * + * <p>The data would be considered valid if and only if: + * + * <ul> + * <li>The number of items in both the arrays are equal + * <li>The item added in this key follows a specific format. Either it should be all numbers, + * or "+" followed by all numbers. + * </ul> + * + * <p>Example: + * + * <pre><code> + * <string-array name="carrier_service_number_array" num="2"> + * <item value="123"/> + * <item value="+343"/> + * </string-array> + * </code></pre> + */ + public static final String KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY = + "carrier_service_number_array"; + + /** * Configs used by ImsServiceEntitlement. */ public static final class ImsServiceEntitlement { @@ -5710,6 +5761,57 @@ public class CarrierConfigManager { public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY = KEY_PREFIX + "capability_type_presence_uce_int_array"; + /** + * Specifies the policy for disabling NR SA mode. Default value is + *{@link #SA_DISABLE_POLICY_NONE}. + * The value set as below: + * <ul> + * <li>0: {@link #SA_DISABLE_POLICY_NONE }</li> + * <li>1: {@link #SA_DISABLE_POLICY_WFC_ESTABLISHED }</li> + * <li>2: {@link #SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED }</li> + * <li>3: {@link #SA_DISABLE_POLICY_VOWIFI_REGISTERED }</li> + * </ul> + * @hide + */ + public static final String KEY_SA_DISABLE_POLICY_INT = KEY_PREFIX + "sa_disable_policy_int"; + + /** @hide */ + @IntDef({ + SA_DISABLE_POLICY_NONE, + SA_DISABLE_POLICY_WFC_ESTABLISHED, + SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED, + SA_DISABLE_POLICY_VOWIFI_REGISTERED + }) + public @interface NrSaDisablePolicy {} + + /** + * Do not disables NR SA mode. + * @hide + */ + public static final int SA_DISABLE_POLICY_NONE = 0; + + /** + * Disables NR SA mode when VoWiFi call is established in order to improve the delay or + * voice mute when the handover from ePDG to NR is not supported in UE or network. + * @hide + */ + public static final int SA_DISABLE_POLICY_WFC_ESTABLISHED = 1; + + /** + * Disables NR SA mode when VoWiFi call is established when VoNR is disabled in order to + * improve the delay or voice mute when the handover from ePDG to NR is not supported + * in UE or network. + * @hide + */ + public static final int SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED = 2; + + /** + * Disables NR SA mode when IMS is registered over WiFi in order to improve the delay or + * voice mute when the handover from ePDG to NR is not supported in UE or network. + * @hide + */ + public static final int SA_DISABLE_POLICY_VOWIFI_REGISTERED = 3; + private Ims() {} private static PersistableBundle getDefaults() { @@ -5781,6 +5883,7 @@ public class CarrierConfigManager { defaults.putInt(KEY_REGISTRATION_RETRY_BASE_TIMER_MILLIS_INT, 30000); defaults.putInt(KEY_REGISTRATION_RETRY_MAX_TIMER_MILLIS_INT, 1800000); defaults.putInt(KEY_REGISTRATION_SUBSCRIBE_EXPIRY_TIMER_SEC_INT, 600000); + defaults.putInt(KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_NONE); defaults.putIntArray( KEY_IPSEC_AUTHENTICATION_ALGORITHMS_INT_ARRAY, @@ -10285,6 +10388,8 @@ public class CarrierConfigManager { new long[] {180000, 180000, 180000, 180000}); sDefaults.putBooleanArray(KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY, new boolean[] {false, false, true, false, false}); + sDefaults.putStringArray(KEY_CARRIER_SERVICE_NAME_STRING_ARRAY, new String[0]); + sDefaults.putStringArray(KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY, new String[0]); } /** diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 286e71c14726..78c61964edfd 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -3652,17 +3652,10 @@ public class SubscriptionManager { } /** - * Enables or disables a subscription. This is currently used in the settings page. It will - * fail and return false if operation is not supported or failed. + * Enable or disable a subscription. This method is same as + * {@link #setUiccApplicationsEnabled(int, boolean)}. * - * To disable an active subscription on a physical (non-Euicc) SIM, - * {@link #canDisablePhysicalSubscription} needs to be true. - * - * <p> - * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required - * - * @param subscriptionId Subscription to be enabled or disabled. It could be a eSIM or pSIM - * subscription. + * @param subscriptionId Subscription to be enabled or disabled. * @param enable whether user is turning it on or off. * * @return whether the operation is successful. @@ -3672,19 +3665,15 @@ public class SubscriptionManager { @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int subscriptionId, boolean enable) { - if (VDBG) { - logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable); - } try { ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { - return iSub.setSubscriptionEnabled(enable, subscriptionId); + iSub.setUiccApplicationsEnabled(enable, subscriptionId); } } catch (RemoteException ex) { - // ignore it + return false; } - - return false; + return true; } /** @@ -3707,11 +3696,7 @@ public class SubscriptionManager { logd("setUiccApplicationsEnabled subId= " + subscriptionId + " enable " + enabled); } try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.setUiccApplicationsEnabled(enabled, subscriptionId); } @@ -3739,11 +3724,7 @@ public class SubscriptionManager { logd("canDisablePhysicalSubscription"); } try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { return iSub.canDisablePhysicalSubscription(); } @@ -3867,10 +3848,15 @@ public class SubscriptionManager { } /** - * DO NOT USE. - * This API is designed for features that are not finished at this point. Do not call this API. + * Get the active subscription id by logical SIM slot index. + * + * @param slotIndex The logical SIM slot index. + * @return The active subscription id. + * + * @throws IllegalArgumentException if the provided slot index is invalid. + * @throws SecurityException if callers do not hold the required permission. + * * @hide - * TODO b/135547512: further clean up */ @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 9b7f24485e9d..c4a501d336bc 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -17914,6 +17914,97 @@ public class TelephonyManager { } /** + * Captures parameters for collection of emergency + * call diagnostic data + * @hide + */ + public static class EmergencyCallDiagnosticParams { + + private boolean mCollectTelecomDumpSys; + private boolean mCollectTelephonyDumpsys; + private boolean mCollectLogcat; + + //logcat lines with this time or greater are collected + //how much is collected is dependent on internal implementation. + //Time represented as milliseconds since January 1, 1970 UTC + private long mLogcatStartTimeMillis; + + + public boolean isTelecomDumpSysCollectionEnabled() { + return mCollectTelecomDumpSys; + } + + public void setTelecomDumpSysCollection(boolean collectTelecomDumpSys) { + mCollectTelecomDumpSys = collectTelecomDumpSys; + } + + public boolean isTelephonyDumpSysCollectionEnabled() { + return mCollectTelephonyDumpsys; + } + + public void setTelephonyDumpSysCollection(boolean collectTelephonyDumpsys) { + mCollectTelephonyDumpsys = collectTelephonyDumpsys; + } + + public boolean isLogcatCollectionEnabled() { + return mCollectLogcat; + } + + public long getLogcatStartTime() + { + return mLogcatStartTimeMillis; + } + + public void setLogcatCollection(boolean collectLogcat, long startTimeMillis) { + mCollectLogcat = collectLogcat; + if(mCollectLogcat) + { + mLogcatStartTimeMillis = startTimeMillis; + } + } + + @Override + public String toString() { + return "EmergencyCallDiagnosticParams{" + + "mCollectTelecomDumpSys=" + mCollectTelecomDumpSys + + ", mCollectTelephonyDumpsys=" + mCollectTelephonyDumpsys + + ", mCollectLogcat=" + mCollectLogcat + + ", mLogcatStartTimeMillis=" + mLogcatStartTimeMillis + + '}'; + } + } + + /** + * Request telephony to persist state for debugging emergency call failures. + * + * @param dropboxTag Tag to use when persisting data to dropbox service. + * + * @see params Parameters controlling what is collected + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.DUMP) + public void persistEmergencyCallDiagnosticData(@NonNull String dropboxTag, + @NonNull EmergencyCallDiagnosticParams params) { + try { + ITelephony telephony = ITelephony.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getTelephonyServiceRegisterer() + .get()); + if (telephony != null) { + telephony.persistEmergencyCallDiagnosticData(dropboxTag, + params.isLogcatCollectionEnabled(), + params.getLogcatStartTime(), + params.isTelecomDumpSysCollectionEnabled(), + params.isTelephonyDumpSysCollectionEnabled()); + } + } catch (RemoteException e) { + Log.e(TAG, "Error while persistEmergencyCallDiagnosticData: " + e); + } + } + + /** * Set the UE's ability to accept/reject null ciphered and null integrity-protected connections. * * The modem is required to ignore this in case of an emergency call. diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 554beb9a35ba..1ce85ba93d95 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1186,7 +1186,6 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mId, other.mId) && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) && Objects.equals(mApnName, other.mApnName) && Objects.equals(mProxyAddress, other.mProxyAddress) diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 632a6874b5f5..6a5380ddb36e 100644 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -265,8 +265,6 @@ interface ISub { String getSubscriptionProperty(int subId, String propKey, String callingPackage, String callingFeatureId); - boolean setSubscriptionEnabled(boolean enable, int subId); - boolean isSubscriptionEnabled(int subId); int getEnabledSubscriptionId(int slotIndex); @@ -277,7 +275,7 @@ interface ISub { boolean canDisablePhysicalSubscription(); - int setUiccApplicationsEnabled(boolean enabled, int subscriptionId); + void setUiccApplicationsEnabled(boolean enabled, int subscriptionId); int setDeviceToDeviceStatusSharing(int sharing, int subId); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index d0de3acdf257..bab08b58339c 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2677,6 +2677,21 @@ interface ITelephony { int getSimStateForSlotIndex(int slotIndex); /** + * Request telephony to persist state for debugging emergency call failures. + * + * @param dropBoxTag Tag to use when persisting data to dropbox service. + * @param enableLogcat whether to collect logcat output + * @param logcatStartTimestampMillis timestamp from when logcat buffers would be persisted + * @param enableTelecomDump whether to collect telecom dumpsys + * @param enableTelephonyDump whether to collect telephony dumpsys + * + * @hide + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.DUMP)") + void persistEmergencyCallDiagnosticData(String dropboxTag, boolean enableLogcat, + long logcatStartTimestampMillis, boolean enableTelecomDump, boolean enableTelephonyDump); + /** * Set whether the radio is able to connect with null ciphering or integrity * algorithms. This is a global setting and will apply to all active subscriptions * and all new subscriptions after this. diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt index 9c3460c124ba..9dc4bf034e66 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -317,8 +317,7 @@ fun FlickerTest.replacesLayer( assertion.then().isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) } if (ignoreSplashscreen) { - assertion.then().isSplashScreenVisibleFor( - ComponentNameMatcher(newLayer.packageName, className = ""), isOptional = true) + assertion.then().isSplashScreenVisibleFor(newLayer, isOptional = true) } assertion.then().isVisible(newLayer) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java index 858cd7672fe3..a8f1b3de564e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java @@ -26,6 +26,8 @@ import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; +import androidx.annotation.Nullable; + /** * Injects gestures given an {@link Instrumentation} object. */ @@ -36,6 +38,13 @@ public class GestureHelper { private final UiAutomation mUiAutomation; /** + * Primary pointer should be cached here for separate release + */ + @Nullable private PointerProperties mPrimaryPtrProp; + @Nullable private PointerCoords mPrimaryPtrCoord; + private long mPrimaryPtrDownTime; + + /** * A pair of floating point values. */ public static class Tuple { @@ -53,6 +62,52 @@ public class GestureHelper { } /** + * Injects a series of {@link MotionEvent}s to simulate a drag gesture without pointer release. + * + * Simulates a drag gesture without releasing the primary pointer. The primary pointer info + * will be cached for potential release later on by {@code releasePrimaryPointer()} + * + * @param startPoint initial coordinates of the primary pointer + * @param endPoint final coordinates of the primary pointer + * @param steps number of steps to take to animate dragging + * @return true if gesture is injected successfully + */ + public boolean dragWithoutRelease(@NonNull Tuple startPoint, + @NonNull Tuple endPoint, int steps) { + PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER); + PointerCoords ptrCoord = getPointerCoord(startPoint.x, startPoint.y, 1, 1); + + PointerProperties[] ptrProps = new PointerProperties[] { ptrProp }; + PointerCoords[] ptrCoords = new PointerCoords[] { ptrCoord }; + + long downTime = SystemClock.uptimeMillis(); + + if (!primaryPointerDown(ptrProp, ptrCoord, downTime)) { + return false; + } + + // cache the primary pointer info for later potential release + mPrimaryPtrProp = ptrProp; + mPrimaryPtrCoord = ptrCoord; + mPrimaryPtrDownTime = downTime; + + return movePointers(ptrProps, ptrCoords, new Tuple[] { endPoint }, downTime, steps); + } + + /** + * Release primary pointer if previous gesture has cached the primary pointer info. + * + * @return true if the release was injected successfully + */ + public boolean releasePrimaryPointer() { + if (mPrimaryPtrProp != null && mPrimaryPtrCoord != null) { + return primaryPointerUp(mPrimaryPtrProp, mPrimaryPtrCoord, mPrimaryPtrDownTime); + } + + return false; + } + + /** * Injects a series of {@link MotionEvent} objects to simulate a pinch gesture. * * @param startPoint1 initial coordinates of the first pointer diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt index de57d06a5619..e497ae4779a7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt @@ -58,6 +58,43 @@ open class PipAppHelper(instrumentation: Instrumentation) : } /** + * Drags the PIP window to the provided final coordinates without releasing the pointer. + */ + fun dragPipWindowAwayFromEdgeWithoutRelease( + wmHelper: WindowManagerStateHelper, + steps: Int + ) { + val initWindowRect = getWindowRect(wmHelper).clone() + + // initial pointer at the center of the window + val initialCoord = GestureHelper.Tuple(initWindowRect.centerX().toFloat(), + initWindowRect.centerY().toFloat()) + + // the offset to the right (or left) of the window center to drag the window to + val offset = 50 + + // the actual final x coordinate with the offset included; + // if the pip window is closer to the right edge of the display the offset is negative + // otherwise the offset is positive + val endX = initWindowRect.centerX() + + offset * (if (isCloserToRightEdge(wmHelper)) -1 else 1) + val finalCoord = GestureHelper.Tuple(endX.toFloat(), initWindowRect.centerY().toFloat()) + + // drag to the final coordinate + gestureHelper.dragWithoutRelease(initialCoord, finalCoord, steps) + } + + /** + * Releases the primary pointer. + * + * Injects the release of the primary pointer if the primary pointer info was cached after + * another gesture was injected without pointer release. + */ + fun releasePipAfterDragging() { + gestureHelper.releasePrimaryPointer() + } + + /** * Drags the PIP window away from the screen edge while not crossing the display center. * * @throws IllegalStateException if default display bounds are not available @@ -72,10 +109,10 @@ open class PipAppHelper(instrumentation: Instrumentation) : val displayRect = wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect ?: throw IllegalStateException("Default display is null") - // the offset to the right of the display center to drag the window to + // the offset to the right (or left) of the display center to drag the window to val offset = 20 - // the actual final x coordinate with the offset included + // the actual final x coordinate with the offset included; // if the pip window is closer to the right edge of the display the offset is positive // otherwise the offset is negative val endX = displayRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) 1 else -1) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt index d72f5288d4d5..6066d2e74209 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt @@ -66,7 +66,7 @@ open class CloseImeOnDismissPopupDialogTest(flicker: FlickerTest) : BaseTest(fli flicker.assertLayers { this.isVisible(ComponentNameMatcher.IME) .then() - .isVisible(ComponentNameMatcher.IME_SNAPSHOT) + .isVisible(ComponentNameMatcher.IME_SNAPSHOT, isOptional = true) .then() .isInvisible(ComponentNameMatcher.IME_SNAPSHOT, isOptional = true) .isInvisible(ComponentNameMatcher.IME) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt index dd9e4cffcd30..3fccd12af1c4 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt @@ -219,9 +219,13 @@ class TaskTransitionTest(flicker: FlickerTest) : BaseTest(flicker) { val resourceId = Resources.getSystem() .getIdentifier("image_wallpaper_component", "string", "android") - return ComponentNameMatcher.unflattenFromString( + // frameworks/base/core/res/res/values/config.xml returns package plus class name, + // but wallpaper layer has only class name + val rawComponentMatcher = ComponentNameMatcher.unflattenFromString( instrumentation.targetContext.resources.getString(resourceId) ) + + return ComponentNameMatcher(rawComponentMatcher.className) } @Parameterized.Parameters(name = "{0}") diff --git a/tests/Internal/src/com/android/internal/os/TimeoutRecordTest.java b/tests/Internal/src/com/android/internal/os/TimeoutRecordTest.java index 0f9663442740..7419ee1230d3 100644 --- a/tests/Internal/src/com/android/internal/os/TimeoutRecordTest.java +++ b/tests/Internal/src/com/android/internal/os/TimeoutRecordTest.java @@ -16,15 +16,15 @@ package com.android.internal.os; -import android.content.ComponentName; -import android.content.Intent; -import android.platform.test.annotations.Presubmit; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import android.content.ComponentName; +import android.content.Intent; +import android.platform.test.annotations.Presubmit; + import androidx.test.filters.SmallTest; import org.junit.Test; @@ -40,7 +40,7 @@ public class TimeoutRecordTest { @Test public void forBroadcastReceiver_returnsCorrectTimeoutRecord() { Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(ComponentName.createRelative("com.example.app", "ExampleClass")); + intent.setComponent(new ComponentName("com.example.app", "com.example.app.ExampleClass")); TimeoutRecord record = TimeoutRecord.forBroadcastReceiver(intent); @@ -48,14 +48,28 @@ public class TimeoutRecordTest { assertEquals(record.mKind, TimeoutRecord.TimeoutKind.BROADCAST_RECEIVER); assertEquals(record.mReason, "Broadcast of Intent { act=android.intent.action.MAIN cmp=com.example" - + ".app/ExampleClass }"); + + ".app/.ExampleClass }"); + assertTrue(record.mEndTakenBeforeLocks); + } + + @Test + public void forBroadcastReceiver_withPackageAndClass_returnsCorrectTimeoutRecord() { + Intent intent = new Intent(Intent.ACTION_MAIN); + TimeoutRecord record = TimeoutRecord.forBroadcastReceiver(intent, + "com.example.app", "com.example.app.ExampleClass"); + + assertNotNull(record); + assertEquals(record.mKind, TimeoutRecord.TimeoutKind.BROADCAST_RECEIVER); + assertEquals(record.mReason, + "Broadcast of Intent { act=android.intent.action.MAIN cmp=com.example" + + ".app/.ExampleClass }"); assertTrue(record.mEndTakenBeforeLocks); } @Test public void forBroadcastReceiver_withTimeoutDurationMs_returnsCorrectTimeoutRecord() { Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(ComponentName.createRelative("com.example.app", "ExampleClass")); + intent.setComponent(new ComponentName("com.example.app", "com.example.app.ExampleClass")); TimeoutRecord record = TimeoutRecord.forBroadcastReceiver(intent, 1000L); @@ -63,7 +77,7 @@ public class TimeoutRecordTest { assertEquals(record.mKind, TimeoutRecord.TimeoutKind.BROADCAST_RECEIVER); assertEquals(record.mReason, "Broadcast of Intent { act=android.intent.action.MAIN cmp=com.example" - + ".app/ExampleClass }, waited 1000ms"); + + ".app/.ExampleClass }, waited 1000ms"); assertTrue(record.mEndTakenBeforeLocks); } diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS index 9db19a37812b..a0fcfc52704d 100644 --- a/tests/SoundTriggerTestApp/OWNERS +++ b/tests/SoundTriggerTestApp/OWNERS @@ -1,2 +1,2 @@ -include /core/java/android/media/soundtrigger/OWNERS +include /media/java/android/media/soundtrigger/OWNERS mdooley@google.com diff --git a/tests/SoundTriggerTests/OWNERS b/tests/SoundTriggerTests/OWNERS index 816bc6bba639..1e41886fe716 100644 --- a/tests/SoundTriggerTests/OWNERS +++ b/tests/SoundTriggerTests/OWNERS @@ -1 +1 @@ -include /core/java/android/media/soundtrigger/OWNERS +include /media/java/android/media/soundtrigger/OWNERS diff --git a/tests/utils/testutils/java/android/os/test/FakePermissionEnforcer.java b/tests/utils/testutils/java/android/os/test/FakePermissionEnforcer.java new file mode 100644 index 000000000000..b94bb41c0988 --- /dev/null +++ b/tests/utils/testutils/java/android/os/test/FakePermissionEnforcer.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.test; + +import static android.permission.PermissionManager.PERMISSION_GRANTED; +import static android.permission.PermissionManager.PERMISSION_HARD_DENIED; + +import android.annotation.NonNull; +import android.content.AttributionSource; +import android.os.PermissionEnforcer; + +import java.util.HashSet; +import java.util.Set; + +/** + * Fake for {@link PermissionEnforcer}. Useful for tests wanting to mock the + * permission checks of an AIDL service. FakePermissionEnforcer may be passed + * to the constructor of the AIDL-generated Stub class. + * + */ +public class FakePermissionEnforcer extends PermissionEnforcer { + private Set<String> mGranted; + + public FakePermissionEnforcer() { + mGranted = new HashSet(); + } + + public void grant(String permission) { + mGranted.add(permission); + } + + public void revoke(String permission) { + mGranted.remove(permission); + } + + private boolean granted(String permission) { + return mGranted.contains(permission); + } + + @Override + protected int checkPermission(@NonNull String permission, + @NonNull AttributionSource source) { + return granted(permission) ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; + } + + @Override + protected int checkPermission(@NonNull String permission, int pid, int uid) { + return granted(permission) ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; + } +} diff --git a/tests/utils/testutils/java/android/os/test/OWNERS b/tests/utils/testutils/java/android/os/test/OWNERS new file mode 100644 index 000000000000..3a9129e1bb69 --- /dev/null +++ b/tests/utils/testutils/java/android/os/test/OWNERS @@ -0,0 +1 @@ +per-file FakePermissionEnforcer.java = file:/tests/EnforcePermission/OWNERS diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 075bc5e5214e..4123f8070e36 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -17,7 +17,9 @@ package com.android.server; import static android.net.ConnectivityManager.NetworkCallback; +import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -67,7 +69,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.net.TelephonyNetworkSpecifier; import android.net.Uri; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -128,6 +129,15 @@ public class VcnManagementServiceTest { private static final VcnConfig TEST_VCN_CONFIG; private static final VcnConfig TEST_VCN_CONFIG_PKG_2; private static final int TEST_UID = Process.FIRST_APPLICATION_UID; + private static final String TEST_IFACE_NAME = "TEST_IFACE"; + private static final String TEST_IFACE_NAME_2 = "TEST_IFACE2"; + private static final LinkProperties TEST_LP_1 = new LinkProperties(); + private static final LinkProperties TEST_LP_2 = new LinkProperties(); + + static { + TEST_LP_1.setInterfaceName(TEST_IFACE_NAME); + TEST_LP_2.setInterfaceName(TEST_IFACE_NAME_2); + } static { final Context mockConfigContext = mock(Context.class); @@ -1034,8 +1044,7 @@ public class VcnManagementServiceTest { setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); return mVcnMgmtSvc.getUnderlyingNetworkPolicy( - getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), - new LinkProperties()); + getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), TEST_LP_1); } private void checkGetRestrictedTransportsFromCarrierConfig( @@ -1260,7 +1269,7 @@ public class VcnManagementServiceTest { false /* expectRestricted */); } - private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { + private void setupTrackedNetwork(NetworkCapabilities caps, LinkProperties lp) { mVcnMgmtSvc.systemReady(); final ArgumentCaptor<NetworkCallback> captor = @@ -1269,7 +1278,10 @@ public class VcnManagementServiceTest { .registerNetworkCallback( eq(new NetworkRequest.Builder().clearCapabilities().build()), captor.capture()); - captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps); + + Network mockNetwork = mock(Network.class, CALLS_REAL_METHODS); + captor.getValue().onCapabilitiesChanged(mockNetwork, caps); + captor.getValue().onLinkPropertiesChanged(mockNetwork, lp); } @Test @@ -1279,7 +1291,7 @@ public class VcnManagementServiceTest { getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) .build(); - setupTrackedCarrierWifiNetwork(existingNetworkCaps); + setupTrackedNetwork(existingNetworkCaps, TEST_LP_1); // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED // immutable capability @@ -1288,7 +1300,7 @@ public class VcnManagementServiceTest { getNetworkCapabilitiesBuilderForTransport( TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) .build(), - new LinkProperties()); + TEST_LP_1); assertTrue(policy.isTeardownRequested()); } @@ -1298,7 +1310,7 @@ public class VcnManagementServiceTest { final NetworkCapabilities existingNetworkCaps = getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) .build(); - setupTrackedCarrierWifiNetwork(existingNetworkCaps); + setupTrackedNetwork(existingNetworkCaps, TEST_LP_1); final VcnUnderlyingNetworkPolicy policy = startVcnAndGetPolicyForTransport( @@ -1315,7 +1327,7 @@ public class VcnManagementServiceTest { .addCapability(NET_CAPABILITY_NOT_RESTRICTED) .removeCapability(NET_CAPABILITY_IMS) .build(); - setupTrackedCarrierWifiNetwork(existingNetworkCaps); + setupTrackedNetwork(existingNetworkCaps, TEST_LP_1); final VcnUnderlyingNetworkPolicy policy = mVcnMgmtSvc.getUnderlyingNetworkPolicy( @@ -1336,7 +1348,7 @@ public class VcnManagementServiceTest { new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2)) + .setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2)) .build(); VcnUnderlyingNetworkPolicy policy = @@ -1346,6 +1358,38 @@ public class VcnManagementServiceTest { assertEquals(nc, policy.getMergedNetworkCapabilities()); } + /** + * Checks that networks with similar capabilities do not clobber each other. + * + * <p>In previous iterations, the VcnMgmtSvc used capability-matching to check if a network + * undergoing policy checks were the same as an existing networks. However, this meant that if + * there were newly added capabilities that the VCN did not check, two networks differing only + * by that capability would restart each other constantly. + */ + @Test + public void testGetUnderlyingNetworkPolicySimilarNetworks() throws Exception { + NetworkCapabilities nc1 = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .addCapability(NET_CAPABILITY_INTERNET) + .setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2)) + .build(); + + NetworkCapabilities nc2 = + new NetworkCapabilities.Builder(nc1) + .addCapability(NET_CAPABILITY_ENTERPRISE) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .build(); + + setupTrackedNetwork(nc1, TEST_LP_1); + + VcnUnderlyingNetworkPolicy policy = mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc2, TEST_LP_2); + + assertFalse(policy.isTeardownRequested()); + assertEquals(nc2, policy.getMergedNetworkCapabilities()); + } + @Test(expected = SecurityException.class) public void testGetUnderlyingNetworkPolicyInvalidPermission() { doReturn(PackageManager.PERMISSION_DENIED) diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 629e988495cc..226604108522 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -95,6 +95,7 @@ public class NetworkPriorityClassifierTest { private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .setSignalStrength(WIFI_RSSI) .setSsid(SSID) .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) @@ -509,12 +510,14 @@ public class NetworkPriorityClassifierTest { VcnCellUnderlyingNetworkTemplate template, boolean expectMatch) { assertEquals( expectMatch, - checkMatchesCellPriorityRule( + checkMatchesPriorityRule( mVcnContext, template, mCellNetworkRecord, SUB_GROUP, - mSubscriptionSnapshot)); + mSubscriptionSnapshot, + null /* currentlySelected */, + null /* carrierConfig */)); } @Test diff --git a/wifi/java/src/android/net/wifi/nl80211/OWNERS b/wifi/java/src/android/net/wifi/nl80211/OWNERS new file mode 100644 index 000000000000..8a75e25cb2f6 --- /dev/null +++ b/wifi/java/src/android/net/wifi/nl80211/OWNERS @@ -0,0 +1 @@ +kumachang@google.com diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java index 15fd817ba73b..e5ef62b16dfd 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java @@ -38,6 +38,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import java.util.HashMap; import java.util.List; @@ -49,9 +50,14 @@ import java.util.concurrent.Executor; * This class is the library used by consumers of Shared Connectivity data to bind to the service, * receive callbacks from, and send user actions to the service. * + * A client must register at least one callback so that the manager will bind to the service. Once + * all callbacks are unregistered, the manager will unbind from the service. When the client no + * longer needs Shared Connectivity data, the client must unregister. + * * The methods {@link #connectHotspotNetwork}, {@link #disconnectHotspotNetwork}, * {@link #connectKnownNetwork} and {@link #forgetKnownNetwork} are not valid and will return false - * if not called between {@link SharedConnectivityClientCallback#onServiceConnected()} + * and getter methods will fail and return null if not called between + * {@link SharedConnectivityClientCallback#onServiceConnected()} * and {@link SharedConnectivityClientCallback#onServiceDisconnected()} or if * {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} was called. * @@ -139,19 +145,22 @@ public class SharedConnectivityManager { } private ISharedConnectivityService mService; + @GuardedBy("mProxyDataLock") private final Map<SharedConnectivityClientCallback, SharedConnectivityCallbackProxy> mProxyMap = new HashMap<>(); + @GuardedBy("mProxyDataLock") private final Map<SharedConnectivityClientCallback, SharedConnectivityCallbackProxy> mCallbackProxyCache = new HashMap<>(); - // Used for testing - private final ServiceConnection mServiceConnection; + // Makes sure mProxyMap and mCallbackProxyCache are locked together when one of them is used. + private final Object mProxyDataLock = new Object(); + private final Context mContext; + private final String mServicePackageName; + private final String mIntentAction; + private ServiceConnection mServiceConnection; /** * Creates a new instance of {@link SharedConnectivityManager}. * - * Automatically binds to implementation of {@link SharedConnectivityService} specified in - * the device overlay. - * * @return An instance of {@link SharedConnectivityManager} or null if the shared connectivity * service is not found. * @hide @@ -185,12 +194,18 @@ public class SharedConnectivityManager { private SharedConnectivityManager(@NonNull Context context, String servicePackageName, String serviceIntentAction) { + mContext = context; + mServicePackageName = servicePackageName; + mIntentAction = serviceIntentAction; + } + + private void bind() { mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = ISharedConnectivityService.Stub.asInterface(service); - if (!mCallbackProxyCache.isEmpty()) { - synchronized (mCallbackProxyCache) { + synchronized (mProxyDataLock) { + if (!mCallbackProxyCache.isEmpty()) { mCallbackProxyCache.keySet().forEach(callback -> registerCallbackInternal( callback, mCallbackProxyCache.get(callback))); @@ -203,15 +218,13 @@ public class SharedConnectivityManager { public void onServiceDisconnected(ComponentName name) { if (DEBUG) Log.i(TAG, "onServiceDisconnected"); mService = null; - if (!mCallbackProxyCache.isEmpty()) { - synchronized (mCallbackProxyCache) { + synchronized (mProxyDataLock) { + if (!mCallbackProxyCache.isEmpty()) { mCallbackProxyCache.keySet().forEach( SharedConnectivityClientCallback::onServiceDisconnected); mCallbackProxyCache.clear(); } - } - if (!mProxyMap.isEmpty()) { - synchronized (mProxyMap) { + if (!mProxyMap.isEmpty()) { mProxyMap.keySet().forEach( SharedConnectivityClientCallback::onServiceDisconnected); mProxyMap.clear(); @@ -220,8 +233,8 @@ public class SharedConnectivityManager { } }; - context.bindService( - new Intent().setPackage(servicePackageName).setAction(serviceIntentAction), + mContext.bindService( + new Intent().setPackage(mServicePackageName).setAction(mIntentAction), mServiceConnection, Context.BIND_AUTO_CREATE); } @@ -229,7 +242,7 @@ public class SharedConnectivityManager { SharedConnectivityCallbackProxy proxy) { try { mService.registerCallback(proxy); - synchronized (mProxyMap) { + synchronized (mProxyDataLock) { mProxyMap.put(callback, proxy); } callback.onServiceConnected(); @@ -256,10 +269,19 @@ public class SharedConnectivityManager { return mServiceConnection; } + private void unbind() { + if (mServiceConnection != null) { + mContext.unbindService(mServiceConnection); + mServiceConnection = null; + } + } + /** * Registers a callback for receiving updates to the list of Hotspot Networks, Known Networks, * shared connectivity settings state, hotspot network connection status and known network * connection status. + * Automatically binds to implementation of {@link SharedConnectivityService} specified in + * the device overlay when the first callback is registered. * The {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} will be called if the * registration failed. * @@ -284,9 +306,16 @@ public class SharedConnectivityManager { SharedConnectivityCallbackProxy proxy = new SharedConnectivityCallbackProxy(executor, callback); if (mService == null) { - synchronized (mCallbackProxyCache) { + boolean shouldBind; + synchronized (mProxyDataLock) { + // Size can be 1 in different cases of register/unregister sequences. If size is 0 + // Bind never happened or unbind was called. + shouldBind = mCallbackProxyCache.size() == 0; mCallbackProxyCache.put(callback, proxy); } + if (shouldBind) { + bind(); + } return; } registerCallbackInternal(callback, proxy); @@ -294,6 +323,7 @@ public class SharedConnectivityManager { /** * Unregisters a callback. + * Unbinds from {@link SharedConnectivityService} when no more callbacks are registered. * * @return Returns true if the callback was successfully unregistered, false otherwise. */ @@ -309,16 +339,27 @@ public class SharedConnectivityManager { } if (mService == null) { - synchronized (mCallbackProxyCache) { + boolean shouldUnbind; + synchronized (mProxyDataLock) { mCallbackProxyCache.remove(callback); + // Connection was never established, so all registered callbacks are in the cache. + shouldUnbind = mCallbackProxyCache.isEmpty(); + } + if (shouldUnbind) { + unbind(); } return true; } try { - mService.unregisterCallback(mProxyMap.get(callback)); - synchronized (mProxyMap) { + boolean shouldUnbind; + synchronized (mProxyDataLock) { + mService.unregisterCallback(mProxyMap.get(callback)); mProxyMap.remove(callback); + shouldUnbind = mProxyMap.isEmpty(); + } + if (shouldUnbind) { + unbind(); } } catch (RemoteException e) { Log.e(TAG, "Exception in unregisterCallback", e); diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java index 96afe278e3e0..b585bd5cfd7b 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java @@ -28,15 +28,17 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; import android.content.res.Resources; import android.net.wifi.sharedconnectivity.service.ISharedConnectivityService; import android.os.Bundle; -import android.os.Parcel; import android.os.RemoteException; import androidx.test.filters.SmallTest; @@ -80,7 +82,7 @@ public class SharedConnectivityManagerTest { @Mock Executor mExecutor; @Mock - SharedConnectivityClientCallback mClientCallback; + SharedConnectivityClientCallback mClientCallback, mClientCallback2; @Mock Resources mResources; @Mock @@ -95,47 +97,52 @@ public class SharedConnectivityManagerTest { setResources(mContext); } - /** - * Verifies constructor is binding to service. - */ @Test - public void bindingToService() { - SharedConnectivityManager.create(mContext); + public void resourcesNotDefined_createShouldReturnNull() { + when(mResources.getString(anyInt())).thenThrow(new Resources.NotFoundException()); - verify(mContext).bindService(any(), any(), anyInt()); + assertThat(SharedConnectivityManager.create(mContext)).isNull(); } - /** - * Verifies create method returns null when resources are not specified - */ @Test - public void resourcesNotDefined() { - when(mResources.getString(anyInt())).thenThrow(new Resources.NotFoundException()); + public void bindingToServiceOnFirstCallbackRegistration() { + SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); + manager.registerCallback(mExecutor, mClientCallback); - assertThat(SharedConnectivityManager.create(mContext)).isNull(); + verify(mContext).bindService(any(Intent.class), any(ServiceConnection.class), anyInt()); } - /** - * Verifies registerCallback behavior. - */ @Test - public void registerCallback_serviceNotConnected_registrationCachedThenConnected() - throws Exception { + public void bindIsCalledOnceOnMultipleCallbackRegistrations() throws Exception { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); - manager.setService(null); manager.registerCallback(mExecutor, mClientCallback); - manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder); + verify(mContext, times(1)).bindService(any(Intent.class), any(ServiceConnection.class), + anyInt()); + + manager.registerCallback(mExecutor, mClientCallback2); + verify(mContext, times(1)).bindService(any(Intent.class), any(ServiceConnection.class), + anyInt()); + } - // Since the binder is embedded in a proxy class, the call to registerCallback is done on - // the proxy. So instead verifying that the proxy is calling the binder. - verify(mIBinder).transact(anyInt(), any(Parcel.class), any(Parcel.class), anyInt()); + @Test + public void unbindIsCalledOnLastCallbackUnregistrations() throws Exception { + SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); + + manager.registerCallback(mExecutor, mClientCallback); + manager.registerCallback(mExecutor, mClientCallback2); + manager.unregisterCallback(mClientCallback); + verify(mContext, never()).unbindService( + any(ServiceConnection.class)); + + manager.unregisterCallback(mClientCallback2); + verify(mContext, times(1)).unbindService( + any(ServiceConnection.class)); } @Test public void registerCallback_serviceNotConnected_canUnregisterAndReregister() { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); - manager.setService(null); manager.registerCallback(mExecutor, mClientCallback); manager.unregisterCallback(mClientCallback); @@ -177,9 +184,6 @@ public class SharedConnectivityManagerTest { verify(mClientCallback).onRegisterCallbackFailed(any(RemoteException.class)); } - /** - * Verifies unregisterCallback behavior. - */ @Test public void unregisterCallback_withoutRegisteringFirst_serviceNotConnected_shouldFail() { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); @@ -239,11 +243,8 @@ public class SharedConnectivityManagerTest { assertThat(manager.unregisterCallback(mClientCallback)).isFalse(); } - /** - * Verifies callback is called when service is connected - */ @Test - public void onServiceConnected_registerCallbackBeforeConnection() { + public void onServiceConnected() { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.registerCallback(mExecutor, mClientCallback); @@ -253,20 +254,7 @@ public class SharedConnectivityManagerTest { } @Test - public void onServiceConnected_registerCallbackAfterConnection() { - SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); - - manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder); - manager.registerCallback(mExecutor, mClientCallback); - - verify(mClientCallback).onServiceConnected(); - } - - /** - * Verifies callback is called when service is disconnected - */ - @Test - public void onServiceDisconnected_registerCallbackBeforeConnection() { + public void onServiceDisconnected() { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.registerCallback(mExecutor, mClientCallback); @@ -276,20 +264,7 @@ public class SharedConnectivityManagerTest { verify(mClientCallback).onServiceDisconnected(); } - @Test - public void onServiceDisconnected_registerCallbackAfterConnection() { - SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); - - manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder); - manager.registerCallback(mExecutor, mClientCallback); - manager.getServiceConnection().onServiceDisconnected(COMPONENT_NAME); - - verify(mClientCallback).onServiceDisconnected(); - } - /** - * Verifies connectHotspotNetwork behavior. - */ @Test public void connectHotspotNetwork_serviceNotConnected_shouldFail() { HotspotNetwork network = buildHotspotNetwork(); @@ -320,9 +295,6 @@ public class SharedConnectivityManagerTest { assertThat(manager.connectHotspotNetwork(network)).isFalse(); } - /** - * Verifies disconnectHotspotNetwork behavior. - */ @Test public void disconnectHotspotNetwork_serviceNotConnected_shouldFail() { HotspotNetwork network = buildHotspotNetwork(); @@ -353,9 +325,6 @@ public class SharedConnectivityManagerTest { assertThat(manager.disconnectHotspotNetwork(network)).isFalse(); } - /** - * Verifies connectKnownNetwork behavior. - */ @Test public void connectKnownNetwork_serviceNotConnected_shouldFail() throws RemoteException { KnownNetwork network = buildKnownNetwork(); @@ -386,9 +355,6 @@ public class SharedConnectivityManagerTest { assertThat(manager.connectKnownNetwork(network)).isFalse(); } - /** - * Verifies forgetKnownNetwork behavior. - */ @Test public void forgetKnownNetwork_serviceNotConnected_shouldFail() { KnownNetwork network = buildKnownNetwork(); @@ -419,9 +385,6 @@ public class SharedConnectivityManagerTest { assertThat(manager.forgetKnownNetwork(network)).isFalse(); } - /** - * Verify getters. - */ @Test public void getHotspotNetworks_serviceNotConnected_shouldReturnNull() { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); |